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,570 @@
1
+ import json
2
+
3
+ import pytest
4
+
5
+ from xfintech.serde.common.dataformat import DataFormat
6
+ from xfintech.serde.common.error import (
7
+ DeserialiserFailedError,
8
+ DeserialiserInputTypeError,
9
+ DeserialiserNotSupportedError,
10
+ )
11
+ from xfintech.serde.deserialiser.python import PythonDeserialiser
12
+ from xfintech.serde.serialiser.python import PythonSerialiser
13
+
14
+ # ==================== Class Structure Tests ====================
15
+
16
+
17
+ def test_pythondeserialiser_has_deserialise_method():
18
+ """Test PythonDeserialiser has deserialise method"""
19
+ assert hasattr(PythonDeserialiser, "deserialise")
20
+ assert callable(PythonDeserialiser.deserialise)
21
+
22
+
23
+ def test_pythondeserialiser_has_from_json_method():
24
+ """Test PythonDeserialiser has from_json method"""
25
+ assert hasattr(PythonDeserialiser, "from_json")
26
+ assert callable(PythonDeserialiser.from_json)
27
+
28
+
29
+ def test_pythondeserialiser_methods_are_static():
30
+ """Test all methods are static methods"""
31
+ assert isinstance(PythonDeserialiser.__dict__["deserialise"], staticmethod)
32
+ assert isinstance(PythonDeserialiser.__dict__["from_json"], staticmethod)
33
+
34
+
35
+ # ==================== deserialise() Method Tests ====================
36
+
37
+
38
+ def test_deserialise_simple_dict():
39
+ """Test deserialise with simple dictionary"""
40
+ data = {"key": "value", "number": 42}
41
+ bytes_data = PythonSerialiser.serialise(data, DataFormat.JSON)
42
+ result = PythonDeserialiser.deserialise(bytes_data, DataFormat.JSON)
43
+ assert isinstance(result, dict)
44
+ assert result == data
45
+
46
+
47
+ def test_deserialise_with_json_format_enum():
48
+ """Test deserialise with JSON DataFormat enum"""
49
+ data = {"a": 1, "b": 2}
50
+ bytes_data = PythonSerialiser.serialise(data, DataFormat.JSON)
51
+ result = PythonDeserialiser.deserialise(bytes_data, DataFormat.JSON)
52
+ assert result == data
53
+
54
+
55
+ def test_deserialise_with_json_format_string_lowercase():
56
+ """Test deserialise with 'json' string"""
57
+ data = {"a": 1}
58
+ bytes_data = PythonSerialiser.serialise(data, DataFormat.JSON)
59
+ result = PythonDeserialiser.deserialise(bytes_data, "json")
60
+ assert result == data
61
+
62
+
63
+ def test_deserialise_with_json_format_string_uppercase():
64
+ """Test deserialise with 'JSON' string"""
65
+ data = {"a": 1}
66
+ bytes_data = PythonSerialiser.serialise(data, DataFormat.JSON)
67
+ result = PythonDeserialiser.deserialise(bytes_data, "JSON")
68
+ assert result == data
69
+
70
+
71
+ def test_deserialise_with_json_format_string_mixed_case():
72
+ """Test deserialise with 'Json' string"""
73
+ data = {"a": 1}
74
+ bytes_data = PythonSerialiser.serialise(data, DataFormat.JSON)
75
+ result = PythonDeserialiser.deserialise(bytes_data, "Json")
76
+ assert result == data
77
+
78
+
79
+ def test_deserialise_returns_dict():
80
+ """Test deserialise returns dict type"""
81
+ data = {"test": "data"}
82
+ bytes_data = PythonSerialiser.serialise(data, DataFormat.JSON)
83
+ result = PythonDeserialiser.deserialise(bytes_data, DataFormat.JSON)
84
+ assert isinstance(result, dict)
85
+
86
+
87
+ def test_deserialise_nested_dict():
88
+ """Test deserialise with nested dictionary"""
89
+ data = {"outer": {"inner": {"deep": "value"}}}
90
+ bytes_data = PythonSerialiser.serialise(data, DataFormat.JSON)
91
+ result = PythonDeserialiser.deserialise(bytes_data, DataFormat.JSON)
92
+ assert result["outer"]["inner"]["deep"] == "value"
93
+
94
+
95
+ def test_deserialise_dict_with_list():
96
+ """Test deserialise with dictionary containing list"""
97
+ data = {"items": [1, 2, 3, 4, 5]}
98
+ bytes_data = PythonSerialiser.serialise(data, DataFormat.JSON)
99
+ result = PythonDeserialiser.deserialise(bytes_data, DataFormat.JSON)
100
+ assert result["items"] == [1, 2, 3, 4, 5]
101
+
102
+
103
+ def test_deserialise_dict_with_various_types():
104
+ """Test deserialise with various data types"""
105
+ data = {
106
+ "string": "text",
107
+ "integer": 42,
108
+ "float": 3.14,
109
+ "boolean": True,
110
+ "null": None,
111
+ "list": [1, 2, 3],
112
+ "nested": {"key": "value"},
113
+ }
114
+ bytes_data = PythonSerialiser.serialise(data, DataFormat.JSON)
115
+ result = PythonDeserialiser.deserialise(bytes_data, DataFormat.JSON)
116
+ assert result == data
117
+
118
+
119
+ def test_deserialise_empty_dict():
120
+ """Test deserialise with empty dictionary"""
121
+ data = {}
122
+ bytes_data = PythonSerialiser.serialise(data, DataFormat.JSON)
123
+ result = PythonDeserialiser.deserialise(bytes_data, DataFormat.JSON)
124
+ assert result == {}
125
+
126
+
127
+ def test_deserialise_large_dict():
128
+ """Test deserialise with large dictionary"""
129
+ data = {f"key_{i}": i for i in range(1000)}
130
+ bytes_data = PythonSerialiser.serialise(data, DataFormat.JSON)
131
+ result = PythonDeserialiser.deserialise(bytes_data, DataFormat.JSON)
132
+ assert len(result) == 1000
133
+
134
+
135
+ def test_deserialise_raises_on_non_bytes_list():
136
+ """Test deserialise raises error for list input"""
137
+ with pytest.raises(DeserialiserInputTypeError) as exc_info:
138
+ PythonDeserialiser.deserialise([1, 2, 3], DataFormat.JSON)
139
+ assert "expects bytes" in str(exc_info.value)
140
+
141
+
142
+ def test_deserialise_raises_on_non_bytes_string():
143
+ """Test deserialise raises error for string input"""
144
+ with pytest.raises(DeserialiserInputTypeError):
145
+ PythonDeserialiser.deserialise("not bytes", DataFormat.JSON)
146
+
147
+
148
+ def test_deserialise_raises_on_non_bytes_dict():
149
+ """Test deserialise raises error for dict input"""
150
+ with pytest.raises(DeserialiserInputTypeError):
151
+ PythonDeserialiser.deserialise({"a": 1}, DataFormat.JSON)
152
+
153
+
154
+ def test_deserialise_raises_on_non_bytes_int():
155
+ """Test deserialise raises error for integer input"""
156
+ with pytest.raises(DeserialiserInputTypeError):
157
+ PythonDeserialiser.deserialise(123, DataFormat.JSON)
158
+
159
+
160
+ def test_deserialise_raises_on_none():
161
+ """Test deserialise raises error for None input"""
162
+ with pytest.raises(DeserialiserInputTypeError):
163
+ PythonDeserialiser.deserialise(None, DataFormat.JSON)
164
+
165
+
166
+ def test_deserialise_raises_on_unsupported_format_parquet():
167
+ """Test deserialise raises error for PARQUET format"""
168
+ bytes_data = b'{"a": 1}'
169
+ with pytest.raises(DeserialiserNotSupportedError) as exc_info:
170
+ PythonDeserialiser.deserialise(bytes_data, DataFormat.PARQUET)
171
+ assert "Unsupported DataFormat" in str(exc_info.value)
172
+
173
+
174
+ def test_deserialise_raises_on_unsupported_format_csv():
175
+ """Test deserialise raises error for CSV format"""
176
+ bytes_data = b'{"a": 1}'
177
+ with pytest.raises(DeserialiserNotSupportedError):
178
+ PythonDeserialiser.deserialise(bytes_data, DataFormat.CSV)
179
+
180
+
181
+ def test_deserialise_raises_on_invalid_format_string():
182
+ """Test deserialise raises error for invalid format string"""
183
+ bytes_data = b'{"a": 1}'
184
+ with pytest.raises(ValueError) as exc_info:
185
+ PythonDeserialiser.deserialise(bytes_data, "xml")
186
+ assert "Unknown DataFormat" in str(exc_info.value)
187
+
188
+
189
+ def test_deserialise_raises_on_invalid_json():
190
+ """Test deserialise raises error for invalid JSON"""
191
+ with pytest.raises(DeserialiserFailedError):
192
+ PythonDeserialiser.deserialise(b"not valid json", DataFormat.JSON)
193
+
194
+
195
+ # ==================== from_json() Method Tests ====================
196
+
197
+
198
+ def test_from_json_basic():
199
+ """Test from_json with basic dictionary"""
200
+ data = {"key": "value"}
201
+ bytes_data = PythonSerialiser.to_json(data)
202
+ result = PythonDeserialiser.from_json(bytes_data)
203
+ assert isinstance(result, dict)
204
+ assert result == data
205
+
206
+
207
+ def test_from_json_returns_dict():
208
+ """Test from_json returns dict type"""
209
+ data = {"test": "data"}
210
+ bytes_data = PythonSerialiser.to_json(data)
211
+ result = PythonDeserialiser.from_json(bytes_data)
212
+ assert isinstance(result, dict)
213
+
214
+
215
+ def test_from_json_with_utf8_encoding():
216
+ """Test from_json with UTF-8 encoding (default)"""
217
+ data = {"text": "Hello 世界"}
218
+ bytes_data = PythonSerialiser.to_json(data)
219
+ result = PythonDeserialiser.from_json(bytes_data)
220
+ assert result["text"] == "Hello 世界"
221
+
222
+
223
+ def test_from_json_with_custom_encoding():
224
+ """Test from_json with custom encoding"""
225
+ data = {"text": "test"}
226
+ bytes_data = PythonSerialiser.to_json(data, encoding="utf-8")
227
+ result = PythonDeserialiser.from_json(bytes_data, encoding="utf-8")
228
+ assert result == data
229
+
230
+
231
+ def test_from_json_with_unicode_characters():
232
+ """Test from_json preserves Unicode"""
233
+ data = {"chinese": "中文", "russian": "Русский", "arabic": "عربي"}
234
+ bytes_data = PythonSerialiser.to_json(data)
235
+ result = PythonDeserialiser.from_json(bytes_data)
236
+ assert result == data
237
+
238
+
239
+ def test_from_json_nested_structure():
240
+ """Test from_json with nested structure"""
241
+ data = {"level1": {"level2": {"level3": "deep value"}}}
242
+ bytes_data = PythonSerialiser.to_json(data)
243
+ result = PythonDeserialiser.from_json(bytes_data)
244
+ assert result["level1"]["level2"]["level3"] == "deep value"
245
+
246
+
247
+ def test_from_json_with_list_values():
248
+ """Test from_json with list values"""
249
+ data = {"numbers": [1, 2, 3, 4, 5], "strings": ["a", "b", "c"]}
250
+ bytes_data = PythonSerialiser.to_json(data)
251
+ result = PythonDeserialiser.from_json(bytes_data)
252
+ assert result["numbers"] == [1, 2, 3, 4, 5]
253
+ assert result["strings"] == ["a", "b", "c"]
254
+
255
+
256
+ def test_from_json_with_null_value():
257
+ """Test from_json with None/null value"""
258
+ data = {"key": None}
259
+ bytes_data = PythonSerialiser.to_json(data)
260
+ result = PythonDeserialiser.from_json(bytes_data)
261
+ assert result["key"] is None
262
+
263
+
264
+ def test_from_json_with_boolean_values():
265
+ """Test from_json with boolean values"""
266
+ data = {"true_val": True, "false_val": False}
267
+ bytes_data = PythonSerialiser.to_json(data)
268
+ result = PythonDeserialiser.from_json(bytes_data)
269
+ assert result["true_val"] is True
270
+ assert result["false_val"] is False
271
+
272
+
273
+ def test_from_json_with_numeric_values():
274
+ """Test from_json with various numeric types"""
275
+ data = {"int": 42, "float": 3.14159, "negative": -100, "zero": 0}
276
+ bytes_data = PythonSerialiser.to_json(data)
277
+ result = PythonDeserialiser.from_json(bytes_data)
278
+ assert result["int"] == 42
279
+ assert abs(result["float"] - 3.14159) < 0.00001
280
+ assert result["negative"] == -100
281
+ assert result["zero"] == 0
282
+
283
+
284
+ def test_from_json_empty_dict():
285
+ """Test from_json with empty dictionary"""
286
+ data = {}
287
+ bytes_data = PythonSerialiser.to_json(data)
288
+ result = PythonDeserialiser.from_json(bytes_data)
289
+ assert result == {}
290
+
291
+
292
+ def test_from_json_single_key():
293
+ """Test from_json with single key dictionary"""
294
+ data = {"only": "one"}
295
+ bytes_data = PythonSerialiser.to_json(data)
296
+ result = PythonDeserialiser.from_json(bytes_data)
297
+ assert result == data
298
+
299
+
300
+ def test_from_json_special_characters_in_values():
301
+ """Test from_json with special characters"""
302
+ data = {
303
+ "quotes": 'He said "hello"',
304
+ "newlines": "line1\nline2",
305
+ "tabs": "col1\tcol2",
306
+ "backslash": "path\\to\\file",
307
+ }
308
+ bytes_data = PythonSerialiser.to_json(data)
309
+ result = PythonDeserialiser.from_json(bytes_data)
310
+ assert result == data
311
+
312
+
313
+ def test_from_json_special_characters_in_keys():
314
+ """Test from_json with special characters in keys"""
315
+ data = {"key with spaces": "value1", "key-with-dashes": "value2", "key.with.dots": "value3"}
316
+ bytes_data = PythonSerialiser.to_json(data)
317
+ result = PythonDeserialiser.from_json(bytes_data)
318
+ assert result == data
319
+
320
+
321
+ def test_from_json_large_dict():
322
+ """Test from_json with large dictionary"""
323
+ data = {f"key_{i}": f"value_{i}" for i in range(1000)}
324
+ bytes_data = PythonSerialiser.to_json(data)
325
+ result = PythonDeserialiser.from_json(bytes_data)
326
+ assert len(result) == 1000
327
+
328
+
329
+ def test_from_json_deeply_nested():
330
+ """Test from_json with deeply nested structure"""
331
+ data = {"a": {"b": {"c": {"d": {"e": {"f": "deep"}}}}}}
332
+ bytes_data = PythonSerialiser.to_json(data)
333
+ result = PythonDeserialiser.from_json(bytes_data)
334
+ assert result["a"]["b"]["c"]["d"]["e"]["f"] == "deep"
335
+
336
+
337
+ def test_from_json_mixed_nesting():
338
+ """Test from_json with mixed nested structures"""
339
+ data = {
340
+ "list_of_dicts": [{"id": 1, "name": "first"}, {"id": 2, "name": "second"}],
341
+ "dict_of_lists": {"group1": [1, 2, 3], "group2": [4, 5, 6]},
342
+ }
343
+ bytes_data = PythonSerialiser.to_json(data)
344
+ result = PythonDeserialiser.from_json(bytes_data)
345
+ assert result == data
346
+
347
+
348
+ def test_from_json_raises_on_invalid_json():
349
+ """Test from_json raises error for invalid JSON"""
350
+ with pytest.raises(DeserialiserFailedError):
351
+ PythonDeserialiser.from_json(b"not valid json")
352
+
353
+
354
+ def test_from_json_raises_on_malformed_json():
355
+ """Test from_json raises error for malformed JSON"""
356
+ with pytest.raises(DeserialiserFailedError):
357
+ PythonDeserialiser.from_json(b'{"key": }')
358
+
359
+
360
+ def test_from_json_can_return_list():
361
+ """Test from_json can deserialise to list (not just dict)"""
362
+ bytes_data = b"[1, 2, 3]"
363
+ result = PythonDeserialiser.from_json(bytes_data)
364
+ assert result == [1, 2, 3]
365
+
366
+
367
+ def test_from_json_can_return_string():
368
+ """Test from_json can deserialise to string"""
369
+ bytes_data = b'"hello"'
370
+ result = PythonDeserialiser.from_json(bytes_data)
371
+ assert result == "hello"
372
+
373
+
374
+ def test_from_json_can_return_number():
375
+ """Test from_json can deserialise to number"""
376
+ bytes_data = b"42"
377
+ result = PythonDeserialiser.from_json(bytes_data)
378
+ assert result == 42
379
+
380
+
381
+ def test_from_json_can_return_boolean():
382
+ """Test from_json can deserialise to boolean"""
383
+ bytes_data = b"true"
384
+ result = PythonDeserialiser.from_json(bytes_data)
385
+ assert result is True
386
+
387
+
388
+ def test_from_json_can_return_null():
389
+ """Test from_json can deserialise to None"""
390
+ bytes_data = b"null"
391
+ result = PythonDeserialiser.from_json(bytes_data)
392
+ assert result is None
393
+
394
+
395
+ # ==================== Roundtrip Tests ====================
396
+
397
+
398
+ def test_roundtrip_serialise_deserialise():
399
+ """Test data can be serialised and deserialised back"""
400
+ original = {"name": "test", "value": 123, "nested": {"key": "value"}, "list": [1, 2, 3]}
401
+
402
+ # Serialise
403
+ bytes_data = PythonSerialiser.serialise(original, DataFormat.JSON)
404
+
405
+ # Deserialise
406
+ result = PythonDeserialiser.deserialise(bytes_data, DataFormat.JSON)
407
+
408
+ assert result == original
409
+
410
+
411
+ def test_roundtrip_to_json_from_json():
412
+ """Test to_json and from_json are inverses"""
413
+ original = {"key1": "value1", "key2": 123, "key3": [1, 2, 3]}
414
+
415
+ bytes_data = PythonSerialiser.to_json(original)
416
+ result = PythonDeserialiser.from_json(bytes_data)
417
+
418
+ assert result == original
419
+
420
+
421
+ def test_roundtrip_preserves_types():
422
+ """Test roundtrip preserves data types"""
423
+ original = {
424
+ "string": "text",
425
+ "int": 42,
426
+ "float": 3.14,
427
+ "bool": True,
428
+ "null": None,
429
+ "list": [1, 2, 3],
430
+ "dict": {"nested": "value"},
431
+ }
432
+
433
+ bytes_data = PythonSerialiser.to_json(original)
434
+ result = PythonDeserialiser.from_json(bytes_data)
435
+
436
+ assert isinstance(result["string"], str)
437
+ assert isinstance(result["int"], int)
438
+ assert isinstance(result["float"], float)
439
+ assert isinstance(result["bool"], bool)
440
+ assert result["null"] is None
441
+ assert isinstance(result["list"], list)
442
+ assert isinstance(result["dict"], dict)
443
+
444
+
445
+ def test_roundtrip_multiple_times():
446
+ """Test multiple roundtrips produce consistent results"""
447
+ original = {"data": "test", "value": 42}
448
+
449
+ # First roundtrip
450
+ bytes1 = PythonSerialiser.to_json(original)
451
+ result1 = PythonDeserialiser.from_json(bytes1)
452
+
453
+ # Second roundtrip
454
+ bytes2 = PythonSerialiser.to_json(result1)
455
+ result2 = PythonDeserialiser.from_json(bytes2)
456
+
457
+ assert result1 == original
458
+ assert result2 == original
459
+
460
+
461
+ def test_roundtrip_with_unicode():
462
+ """Test roundtrip with Unicode data"""
463
+ original = {
464
+ "latin": "Hello",
465
+ "cyrillic": "Привет",
466
+ "arabic": "مرحبا",
467
+ "chinese": "你好",
468
+ "japanese": "こんにちは",
469
+ "korean": "안녕하세요",
470
+ "emoji": "👋🌍",
471
+ }
472
+
473
+ bytes_data = PythonSerialiser.to_json(original)
474
+ result = PythonDeserialiser.from_json(bytes_data)
475
+
476
+ assert result == original
477
+
478
+
479
+ def test_roundtrip_empty_dict():
480
+ """Test roundtrip with empty dictionary"""
481
+ original = {}
482
+ bytes_data = PythonSerialiser.to_json(original)
483
+ result = PythonDeserialiser.from_json(bytes_data)
484
+ assert result == {}
485
+
486
+
487
+ def test_roundtrip_with_empty_strings():
488
+ """Test roundtrip with empty string values"""
489
+ original = {"empty": "", "not_empty": "value"}
490
+ bytes_data = PythonSerialiser.to_json(original)
491
+ result = PythonDeserialiser.from_json(bytes_data)
492
+ assert result == original
493
+
494
+
495
+ def test_roundtrip_with_empty_lists():
496
+ """Test roundtrip with empty list values"""
497
+ original = {"empty_list": [], "list": [1, 2]}
498
+ bytes_data = PythonSerialiser.to_json(original)
499
+ result = PythonDeserialiser.from_json(bytes_data)
500
+ assert result == original
501
+
502
+
503
+ def test_roundtrip_with_empty_nested_dicts():
504
+ """Test roundtrip with empty nested dictionaries"""
505
+ original = {"outer": {}, "another": {"inner": {}}}
506
+ bytes_data = PythonSerialiser.to_json(original)
507
+ result = PythonDeserialiser.from_json(bytes_data)
508
+ assert result == original
509
+
510
+
511
+ # ==================== Integration and Edge Case Tests ====================
512
+
513
+
514
+ def test_deserialise_and_from_json_produce_same_result():
515
+ """Test deserialise and from_json produce same result"""
516
+ bytes_data = b'{"a": 1, "b": 2}'
517
+ result1 = PythonDeserialiser.deserialise(bytes_data, DataFormat.JSON)
518
+ result2 = PythonDeserialiser.from_json(bytes_data)
519
+ assert result1 == result2
520
+
521
+
522
+ def test_from_json_with_very_long_strings():
523
+ """Test from_json with very long string values"""
524
+ long_string = "x" * 100000
525
+ data = {"long": long_string}
526
+ bytes_data = PythonSerialiser.to_json(data)
527
+ result = PythonDeserialiser.from_json(bytes_data)
528
+ assert result["long"] == long_string
529
+
530
+
531
+ def test_from_json_with_numeric_string_keys():
532
+ """Test from_json with numeric string keys"""
533
+ data = {"1": "one", "2": "two", "10": "ten"}
534
+ bytes_data = PythonSerialiser.to_json(data)
535
+ result = PythonDeserialiser.from_json(bytes_data)
536
+ assert result["1"] == "one"
537
+ assert result["2"] == "two"
538
+ assert result["10"] == "ten"
539
+
540
+
541
+ def test_from_json_preserves_order():
542
+ """Test from_json preserves key order (in Python 3.7+)"""
543
+ data = {"z": 1, "a": 2, "m": 3}
544
+ bytes_data = json.dumps(data).encode("utf-8")
545
+ result = PythonDeserialiser.from_json(bytes_data)
546
+ # Note: Order preservation depends on json.dumps maintaining order
547
+ assert list(result.keys()) == ["z", "a", "m"]
548
+
549
+
550
+ def test_output_decoding_consistency():
551
+ """Test output is consistently decoded"""
552
+ data = {"text": "test"}
553
+ bytes_data = PythonSerialiser.to_json(data)
554
+ result = PythonDeserialiser.from_json(bytes_data)
555
+ assert isinstance(result, dict)
556
+ assert isinstance(result["text"], str)
557
+
558
+
559
+ def test_from_json_with_escaped_characters():
560
+ """Test from_json handles escaped characters"""
561
+ bytes_data = b'{"text": "line1\\nline2"}'
562
+ result = PythonDeserialiser.from_json(bytes_data)
563
+ assert result["text"] == "line1\nline2"
564
+
565
+
566
+ def test_from_json_with_unicode_escape_sequences():
567
+ """Test from_json handles Unicode escape sequences"""
568
+ bytes_data = b'{"text": "\\u4e2d\\u6587"}'
569
+ result = PythonDeserialiser.from_json(bytes_data)
570
+ assert result["text"] == "中文"
@@ -0,0 +1,7 @@
1
+ from .pandas import PandasSerialiser
2
+ from .python import PythonSerialiser
3
+
4
+ __all__ = [
5
+ "PandasSerialiser",
6
+ "PythonSerialiser",
7
+ ]
@@ -0,0 +1,116 @@
1
+ from __future__ import annotations
2
+
3
+ from io import BytesIO
4
+ from typing import Any
5
+
6
+ import pandas as pd
7
+
8
+ from xfintech.serde.common.dataformat import DataFormat
9
+ from xfintech.serde.common.error import (
10
+ SerialiserFailedError,
11
+ SerialiserImportError,
12
+ SerialiserInputTypeError,
13
+ SerialiserNotSupportedError,
14
+ )
15
+ from xfintech.serde.common.serialiserlike import SerialiserLike
16
+
17
+
18
+ class PandasSerialiser(SerialiserLike):
19
+ """
20
+ 描述:
21
+ - PandasSerialiser序列化模块。
22
+ - DataFrame -> BYTES 的转换,支持多种常见数据格式(Parquet、CSV、JSON)。
23
+
24
+ 方法:
25
+ - serialise(data, format, **kwargs): 通用序列化方法,支持多种格式。
26
+ - to_parquet(data, **kwargs): 将 DataFrame 序列化为 Parquet 格式的字节流。
27
+ - to_csv(data, **kwargs): 将 DataFrame 序列化为 CSV 格式的字节流。
28
+ - to_json(data, **kwargs): 将 DataFrame 序列化为 JSON 格式的字节流。
29
+
30
+ 例子:
31
+ ```python
32
+ from xfintech.serde.serialiser.pandas import PandasSerialiser
33
+ from xfintech.serde.common.dataformat import DataFormat
34
+ import pandas as pd
35
+
36
+ # 使用通用序列化方法(推荐)
37
+ bytes = PandasSerialiser.serialise(
38
+ df,
39
+ format=DataFormat.PARQUET,
40
+ )
41
+ ```
42
+ """
43
+
44
+ @staticmethod
45
+ def serialise(
46
+ data: pd.DataFrame,
47
+ format: DataFormat | str,
48
+ **kwargs: Any,
49
+ ) -> bytes:
50
+ if not isinstance(data, pd.DataFrame):
51
+ msg = f"PandasSerialiser.serialise expects pd.DataFrame, got {type(data)}"
52
+ raise SerialiserInputTypeError(msg)
53
+
54
+ format = DataFormat.from_any(format)
55
+ if format == DataFormat.PARQUET:
56
+ return PandasSerialiser.to_parquet(data, **kwargs)
57
+ elif format == DataFormat.CSV:
58
+ return PandasSerialiser.to_csv(data, **kwargs)
59
+ elif format == DataFormat.JSON:
60
+ return PandasSerialiser.to_json(data, **kwargs)
61
+ else:
62
+ msg = f"Unsupported DataFormat for serialization: {format}"
63
+ raise SerialiserNotSupportedError(msg)
64
+
65
+ @staticmethod
66
+ def to_parquet(
67
+ data: pd.DataFrame,
68
+ **kwargs: Any,
69
+ ) -> bytes:
70
+ kwargs.setdefault("index", False)
71
+ kwargs.setdefault("engine", "pyarrow")
72
+ kwargs.setdefault("coerce_timestamps", "us")
73
+ kwargs.setdefault("allow_truncated_timestamps", True)
74
+ buffer = BytesIO()
75
+ try:
76
+ data.to_parquet(buffer, **kwargs)
77
+ return buffer.getvalue()
78
+ except ImportError as e:
79
+ msg = "pyarrow is required for parquet serialization. install via 'pip install pyarrow'."
80
+ raise SerialiserImportError(msg) from e
81
+ except Exception as e:
82
+ msg = f"Failed to serialize data: {e}"
83
+ raise SerialiserFailedError(msg) from e
84
+
85
+ @staticmethod
86
+ def to_csv(
87
+ data: pd.DataFrame,
88
+ **kwargs: Any,
89
+ ) -> bytes:
90
+ kwargs.setdefault("index", False)
91
+ encoding = kwargs.pop("encoding", "utf-8")
92
+ try:
93
+ text = data.to_csv(**kwargs)
94
+ return text.encode(encoding)
95
+ except Exception as e:
96
+ msg = f"Failed to serialize data: {e}"
97
+ raise SerialiserFailedError(msg) from e
98
+
99
+ @staticmethod
100
+ def to_json(
101
+ data: pd.DataFrame,
102
+ **kwargs: Any,
103
+ ) -> bytes:
104
+ encoding = kwargs.pop("encoding", "utf-8")
105
+ orient = kwargs.pop("orient", "records")
106
+ lines = kwargs.pop("lines", False)
107
+ try:
108
+ text = data.to_json(
109
+ orient=orient,
110
+ lines=lines,
111
+ **kwargs,
112
+ )
113
+ return text.encode(encoding)
114
+ except Exception as e:
115
+ msg = f"Failed to serialize data: {e}"
116
+ raise SerialiserFailedError(msg) from e