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.
- lib_x17_fintech-2.1.3.dist-info/METADATA +633 -0
- lib_x17_fintech-2.1.3.dist-info/RECORD +282 -0
- lib_x17_fintech-2.1.3.dist-info/WHEEL +5 -0
- lib_x17_fintech-2.1.3.dist-info/licenses/LICENSE +1 -0
- lib_x17_fintech-2.1.3.dist-info/top_level.txt +1 -0
- xfintech/__init__.py +0 -0
- xfintech/connect/__init__.py +18 -0
- xfintech/connect/artifact/__init__.py +5 -0
- xfintech/connect/artifact/artifact.py +168 -0
- xfintech/connect/artifact/tests/__init__.py +3 -0
- xfintech/connect/artifact/tests/test_class_artifact_all.py +564 -0
- xfintech/connect/common/__init__.py +12 -0
- xfintech/connect/common/connect.py +49 -0
- xfintech/connect/common/connectref.py +119 -0
- xfintech/connect/common/error.py +62 -0
- xfintech/connect/common/tests/__init__.py +1 -0
- xfintech/connect/common/tests/test_class_connectlike_all.py +544 -0
- xfintech/connect/common/tests/test_class_connectref_all.py +586 -0
- xfintech/connect/common/tests/test_class_errors_all.py +524 -0
- xfintech/connect/instance/__init__.py +7 -0
- xfintech/connect/instance/macos.py +121 -0
- xfintech/connect/instance/s3.py +176 -0
- xfintech/connect/instance/tests/__init__.py +1 -0
- xfintech/connect/instance/tests/test_class_macosconnect_all.py +692 -0
- xfintech/connect/instance/tests/test_class_s3connect_all.py +603 -0
- xfintech/data/__init__.py +20 -0
- xfintech/data/common/__init__.py +15 -0
- xfintech/data/common/cache.py +186 -0
- xfintech/data/common/coolant.py +171 -0
- xfintech/data/common/metric.py +138 -0
- xfintech/data/common/paginate.py +132 -0
- xfintech/data/common/params.py +162 -0
- xfintech/data/common/retry.py +201 -0
- xfintech/data/common/tests/__init__.py +1 -0
- xfintech/data/common/tests/test_class_cache_all.py +681 -0
- xfintech/data/common/tests/test_class_coolant_all.py +534 -0
- xfintech/data/common/tests/test_class_metric_all.py +705 -0
- xfintech/data/common/tests/test_class_paginate_all.py +508 -0
- xfintech/data/common/tests/test_class_params_all.py +891 -0
- xfintech/data/common/tests/test_class_retry_all.py +714 -0
- xfintech/data/job/__init__.py +17 -0
- xfintech/data/job/errors.py +112 -0
- xfintech/data/job/house.py +156 -0
- xfintech/data/job/job.py +247 -0
- xfintech/data/job/joblike.py +47 -0
- xfintech/data/job/tests/__init__.py +1 -0
- xfintech/data/job/tests/test_class_errors_all.py +275 -0
- xfintech/data/job/tests/test_class_house_all.py +801 -0
- xfintech/data/job/tests/test_class_job_all.py +684 -0
- xfintech/data/job/tests/test_class_joblike_all.py +482 -0
- xfintech/data/relay/__init__.py +7 -0
- xfintech/data/relay/client.py +114 -0
- xfintech/data/relay/clientlike.py +45 -0
- xfintech/data/relay/tests/test_class_relayclient_all.py +484 -0
- xfintech/data/relay/tests/test_class_relayclientlike_all.py +500 -0
- xfintech/data/source/__init__.py +7 -0
- xfintech/data/source/baostock/__init__.py +21 -0
- xfintech/data/source/baostock/job/__init__.py +5 -0
- xfintech/data/source/baostock/job/job.py +217 -0
- xfintech/data/source/baostock/job/tests/__init__.py +0 -0
- xfintech/data/source/baostock/job/tests/test_class_baostockjob_all.py +547 -0
- xfintech/data/source/baostock/session/__init__.py +8 -0
- xfintech/data/source/baostock/session/relay.py +223 -0
- xfintech/data/source/baostock/session/session.py +241 -0
- xfintech/data/source/baostock/session/tests/__init__.py +0 -0
- xfintech/data/source/baostock/session/tests/test_class_relay_all.py +694 -0
- xfintech/data/source/baostock/session/tests/test_class_session_all.py +505 -0
- xfintech/data/source/baostock/stock/__init__.py +0 -0
- xfintech/data/source/baostock/stock/hs300stock/__init__.py +3 -0
- xfintech/data/source/baostock/stock/hs300stock/constant.py +49 -0
- xfintech/data/source/baostock/stock/hs300stock/hs300stock.py +133 -0
- xfintech/data/source/baostock/stock/hs300stock/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/hs300stock/tests/test_class_hs300index_all.py +413 -0
- xfintech/data/source/baostock/stock/minuteline/__init__.py +19 -0
- xfintech/data/source/baostock/stock/minuteline/constant.py +89 -0
- xfintech/data/source/baostock/stock/minuteline/minuteline.py +163 -0
- xfintech/data/source/baostock/stock/minuteline/tests/__init__.py +0 -0
- xfintech/data/source/baostock/stock/minuteline/tests/test_class_minuteline_all.py +582 -0
- xfintech/data/source/baostock/stock/stock/__init__.py +19 -0
- xfintech/data/source/baostock/stock/stock/constant.py +55 -0
- xfintech/data/source/baostock/stock/stock/stock.py +149 -0
- xfintech/data/source/baostock/stock/stock/tests/__init__.py +0 -0
- xfintech/data/source/baostock/stock/stock/tests/test_class_stock_all.py +508 -0
- xfintech/data/source/baostock/stock/stockinfo/__init__.py +5 -0
- xfintech/data/source/baostock/stock/stockinfo/constant.py +66 -0
- xfintech/data/source/baostock/stock/stockinfo/stockinfo.py +176 -0
- xfintech/data/source/baostock/stock/stockinfo/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/stockinfo/tests/test_class_stockinfo_all.py +617 -0
- xfintech/data/source/baostock/stock/sz50stock/__init__.py +3 -0
- xfintech/data/source/baostock/stock/sz50stock/constant.py +49 -0
- xfintech/data/source/baostock/stock/sz50stock/sz50stock.py +133 -0
- xfintech/data/source/baostock/stock/sz50stock/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/sz50stock/tests/test_class_sz50stock_all.py +397 -0
- xfintech/data/source/baostock/stock/tradedate/__init__.py +19 -0
- xfintech/data/source/baostock/stock/tradedate/constant.py +72 -0
- xfintech/data/source/baostock/stock/tradedate/tests/__init__.py +0 -0
- xfintech/data/source/baostock/stock/tradedate/tests/test_class_tradedate_all.py +695 -0
- xfintech/data/source/baostock/stock/tradedate/tradedate.py +208 -0
- xfintech/data/source/baostock/stock/zz500stock/__init__.py +3 -0
- xfintech/data/source/baostock/stock/zz500stock/constant.py +55 -0
- xfintech/data/source/baostock/stock/zz500stock/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/zz500stock/tests/test_class_zz500stock_all.py +421 -0
- xfintech/data/source/baostock/stock/zz500stock/zz500stock.py +133 -0
- xfintech/data/source/tushare/__init__.py +61 -0
- xfintech/data/source/tushare/job/__init__.py +5 -0
- xfintech/data/source/tushare/job/job.py +257 -0
- xfintech/data/source/tushare/job/tests/test_class_tusharejob_all.py +589 -0
- xfintech/data/source/tushare/session/__init__.py +5 -0
- xfintech/data/source/tushare/session/relay.py +231 -0
- xfintech/data/source/tushare/session/session.py +239 -0
- xfintech/data/source/tushare/session/tests/test_class_relay_all.py +719 -0
- xfintech/data/source/tushare/session/tests/test_class_session_all.py +705 -0
- xfintech/data/source/tushare/stock/__init__.py +55 -0
- xfintech/data/source/tushare/stock/adjfactor/__init__.py +19 -0
- xfintech/data/source/tushare/stock/adjfactor/adjfactor.py +150 -0
- xfintech/data/source/tushare/stock/adjfactor/constant.py +71 -0
- xfintech/data/source/tushare/stock/adjfactor/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/adjfactor/tests/test_class_adjfactor_all.py +372 -0
- xfintech/data/source/tushare/stock/capflow/__init__.py +19 -0
- xfintech/data/source/tushare/stock/capflow/capflow.py +171 -0
- xfintech/data/source/tushare/stock/capflow/constant.py +105 -0
- xfintech/data/source/tushare/stock/capflow/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/capflow/tests/test_class_capflow_all.py +589 -0
- xfintech/data/source/tushare/stock/capflowdc/__init__.py +19 -0
- xfintech/data/source/tushare/stock/capflowdc/capflowdc.py +167 -0
- xfintech/data/source/tushare/stock/capflowdc/constant.py +95 -0
- xfintech/data/source/tushare/stock/capflowdc/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/capflowdc/tests/test_class_capflowdc_all.py +814 -0
- xfintech/data/source/tushare/stock/capflowths/__init__.py +19 -0
- xfintech/data/source/tushare/stock/capflowths/capflowths.py +173 -0
- xfintech/data/source/tushare/stock/capflowths/constant.py +92 -0
- xfintech/data/source/tushare/stock/capflowths/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/capflowths/tests/test_class_capflowths_all.py +551 -0
- xfintech/data/source/tushare/stock/company/__init__.py +19 -0
- xfintech/data/source/tushare/stock/company/company.py +188 -0
- xfintech/data/source/tushare/stock/company/constant.py +92 -0
- xfintech/data/source/tushare/stock/company/tests/__init__.py +1 -0
- xfintech/data/source/tushare/stock/company/tests/test_class_company_all.py +829 -0
- xfintech/data/source/tushare/stock/companybusiness/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companybusiness/companybusiness.py +183 -0
- xfintech/data/source/tushare/stock/companybusiness/constant.py +91 -0
- xfintech/data/source/tushare/stock/companybusiness/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companybusiness/tests/test_class_companybusiness_all.py +633 -0
- xfintech/data/source/tushare/stock/companycashflow/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companycashflow/companycashflow.py +277 -0
- xfintech/data/source/tushare/stock/companycashflow/constant.py +293 -0
- xfintech/data/source/tushare/stock/companycashflow/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companycashflow/tests/test_class_companycashflow_all.py +619 -0
- xfintech/data/source/tushare/stock/companydebt/__init__.py +19 -0
- xfintech/data/source/tushare/stock/companydebt/companydebt.py +339 -0
- xfintech/data/source/tushare/stock/companydebt/constant.py +403 -0
- xfintech/data/source/tushare/stock/companydebt/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companydebt/tests/test_class_companydebt_all.py +655 -0
- xfintech/data/source/tushare/stock/companyoverview/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companyoverview/companyoverview.py +214 -0
- xfintech/data/source/tushare/stock/companyoverview/constant.py +152 -0
- xfintech/data/source/tushare/stock/companyoverview/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companyoverview/tests/test_class_companyoverview_all.py +647 -0
- xfintech/data/source/tushare/stock/companyprofit/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companyprofit/companyprofit.py +272 -0
- xfintech/data/source/tushare/stock/companyprofit/constant.py +259 -0
- xfintech/data/source/tushare/stock/companyprofit/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companyprofit/tests/test_class_companyprofit_all.py +635 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/__init__.py +21 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/conceptcapflowdc.py +175 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/constant.py +106 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/tests/test_class_conceptcapflowdc_all.py +568 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/__init__.py +21 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/conceptcapflowths.py +188 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/constant.py +89 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/tests/test_class_conceptcapflowths_all.py +516 -0
- xfintech/data/source/tushare/stock/dayline/__init__.py +19 -0
- xfintech/data/source/tushare/stock/dayline/constant.py +87 -0
- xfintech/data/source/tushare/stock/dayline/dayline.py +177 -0
- xfintech/data/source/tushare/stock/dayline/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/dayline/tests/test_class_dayline_all.py +585 -0
- xfintech/data/source/tushare/stock/industrycapflowths/__init__.py +21 -0
- xfintech/data/source/tushare/stock/industrycapflowths/constant.py +89 -0
- xfintech/data/source/tushare/stock/industrycapflowths/industrycapflowths.py +192 -0
- xfintech/data/source/tushare/stock/industrycapflowths/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/industrycapflowths/tests/test_class_industrycapflowths_all.py +683 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/__init__.py +21 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/constant.py +90 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/marketindexcapflowdc.py +173 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/tests/test_class_marketindexcapflowdc_all.py +793 -0
- xfintech/data/source/tushare/stock/monthline/__init__.py +19 -0
- xfintech/data/source/tushare/stock/monthline/constant.py +87 -0
- xfintech/data/source/tushare/stock/monthline/monthline.py +180 -0
- xfintech/data/source/tushare/stock/monthline/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/monthline/tests/test_class_monthline_all.py +574 -0
- xfintech/data/source/tushare/stock/stock/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stock/constant.py +105 -0
- xfintech/data/source/tushare/stock/stock/stock.py +193 -0
- xfintech/data/source/tushare/stock/stock/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stock/tests/test_class_stock_all.py +788 -0
- xfintech/data/source/tushare/stock/stockdividend/__init__.py +21 -0
- xfintech/data/source/tushare/stock/stockdividend/constant.py +111 -0
- xfintech/data/source/tushare/stock/stockdividend/stockdividend.py +180 -0
- xfintech/data/source/tushare/stock/stockdividend/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockdividend/tests/test_class_stockdividend_all.py +725 -0
- xfintech/data/source/tushare/stock/stockinfo/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockinfo/constant.py +104 -0
- xfintech/data/source/tushare/stock/stockinfo/stockinfo.py +208 -0
- xfintech/data/source/tushare/stock/stockinfo/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockinfo/tests/test_class_stockinfo_all.py +881 -0
- xfintech/data/source/tushare/stock/stockipo/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockipo/constant.py +90 -0
- xfintech/data/source/tushare/stock/stockipo/stockipo.py +234 -0
- xfintech/data/source/tushare/stock/stockipo/tests/__init__.py +1 -0
- xfintech/data/source/tushare/stock/stockipo/tests/test_class_stockipo_all.py +750 -0
- xfintech/data/source/tushare/stock/stockpledge/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockpledge/constant.py +72 -0
- xfintech/data/source/tushare/stock/stockpledge/stockpledge.py +158 -0
- xfintech/data/source/tushare/stock/stockpledge/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockpledge/tests/test_class_stockpledge_all.py +664 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/__init__.py +21 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/constant.py +85 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/stockpledgedetail.py +171 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/tests/test_class_stockpledgedetail_all.py +112 -0
- xfintech/data/source/tushare/stock/stockst/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockst/constant.py +80 -0
- xfintech/data/source/tushare/stock/stockst/stockst.py +189 -0
- xfintech/data/source/tushare/stock/stockst/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockst/tests/test_class_stockst_all.py +693 -0
- xfintech/data/source/tushare/stock/stocksuspend/__init__.py +21 -0
- xfintech/data/source/tushare/stock/stocksuspend/constant.py +75 -0
- xfintech/data/source/tushare/stock/stocksuspend/stocksuspend.py +151 -0
- xfintech/data/source/tushare/stock/stocksuspend/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stocksuspend/tests/test_class_stocksuspend_all.py +626 -0
- xfintech/data/source/tushare/stock/techindex/__init__.py +19 -0
- xfintech/data/source/tushare/stock/techindex/constant.py +600 -0
- xfintech/data/source/tushare/stock/techindex/techindex.py +314 -0
- xfintech/data/source/tushare/stock/techindex/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/techindex/tests/test_class_techindex_all.py +576 -0
- xfintech/data/source/tushare/stock/tradedate/__init__.py +19 -0
- xfintech/data/source/tushare/stock/tradedate/constant.py +93 -0
- xfintech/data/source/tushare/stock/tradedate/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/tradedate/tests/test_class_tradedate_all.py +947 -0
- xfintech/data/source/tushare/stock/tradedate/tradedate.py +234 -0
- xfintech/data/source/tushare/stock/weekline/__init__.py +19 -0
- xfintech/data/source/tushare/stock/weekline/constant.py +87 -0
- xfintech/data/source/tushare/stock/weekline/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/weekline/tests/test_class_weekline_all.py +575 -0
- xfintech/data/source/tushare/stock/weekline/weekline.py +182 -0
- xfintech/fabric/__init__.py +18 -0
- xfintech/fabric/column/__init__.py +7 -0
- xfintech/fabric/column/info.py +202 -0
- xfintech/fabric/column/kind.py +102 -0
- xfintech/fabric/column/tests/__init__.py +0 -0
- xfintech/fabric/column/tests/test_class_info_all.py +207 -0
- xfintech/fabric/column/tests/test_class_kind_all.py +80 -0
- xfintech/fabric/table/__init__.py +5 -0
- xfintech/fabric/table/info.py +263 -0
- xfintech/fabric/table/tests/__init__.py +0 -0
- xfintech/fabric/table/tests/test_class_info_all.py +547 -0
- xfintech/serde/__init__.py +35 -0
- xfintech/serde/common/__init__.py +9 -0
- xfintech/serde/common/dataformat.py +78 -0
- xfintech/serde/common/deserialiserlike.py +38 -0
- xfintech/serde/common/error.py +182 -0
- xfintech/serde/common/serialiserlike.py +38 -0
- xfintech/serde/common/tests/__init__.py +1 -0
- xfintech/serde/common/tests/test_class_dataformat_all.py +694 -0
- xfintech/serde/common/tests/test_class_deserialiserlike_all.py +500 -0
- xfintech/serde/common/tests/test_class_errors_all.py +518 -0
- xfintech/serde/common/tests/test_class_serialiserlike_all.py +401 -0
- xfintech/serde/deserialiser/__init__.py +7 -0
- xfintech/serde/deserialiser/pandas.py +113 -0
- xfintech/serde/deserialiser/python.py +68 -0
- xfintech/serde/deserialiser/tests/__init__.py +1 -0
- xfintech/serde/deserialiser/tests/test_class_pandasdeserialiser_all.py +503 -0
- xfintech/serde/deserialiser/tests/test_class_pythondeserialiser_all.py +570 -0
- xfintech/serde/serialiser/__init__.py +7 -0
- xfintech/serde/serialiser/pandas.py +116 -0
- xfintech/serde/serialiser/python.py +71 -0
- xfintech/serde/serialiser/tests/__init__.py +1 -0
- xfintech/serde/serialiser/tests/test_class_pandasserialiser_all.py +474 -0
- xfintech/serde/serialiser/tests/test_class_pythonserialiser_all.py +508 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
"""
|
|
2
|
+
描述:
|
|
3
|
+
- SerialiserLike 协议的单元测试。
|
|
4
|
+
- 测试协议的结构、实现和运行时类型检查。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from xfintech.serde.common.dataformat import DataFormat
|
|
12
|
+
from xfintech.serde.common.serialiserlike import SerialiserLike
|
|
13
|
+
|
|
14
|
+
# =============================================================================
|
|
15
|
+
# Protocol Structure Tests
|
|
16
|
+
# =============================================================================
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_serialiserlike_is_protocol():
|
|
20
|
+
"""测试 SerialiserLike 是一个协议类"""
|
|
21
|
+
from typing import Protocol
|
|
22
|
+
|
|
23
|
+
assert issubclass(SerialiserLike.__class__, type(Protocol))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_serialiserlike_has_serialise_method():
|
|
27
|
+
"""测试 SerialiserLike 定义了 serialise 方法"""
|
|
28
|
+
assert hasattr(SerialiserLike, "serialise")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_serialiserlike_method_signature():
|
|
32
|
+
"""测试 serialise 方法签名"""
|
|
33
|
+
import inspect
|
|
34
|
+
|
|
35
|
+
sig = inspect.signature(SerialiserLike.serialise)
|
|
36
|
+
params = list(sig.parameters.keys())
|
|
37
|
+
assert "data" in params
|
|
38
|
+
assert "format" in params
|
|
39
|
+
assert "kwargs" in params
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# =============================================================================
|
|
43
|
+
# Implementation Tests - Valid Implementations
|
|
44
|
+
# =============================================================================
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_valid_implementation_with_staticmethod():
|
|
48
|
+
"""测试使用 staticmethod 的有效实现"""
|
|
49
|
+
|
|
50
|
+
class ValidSerialiser:
|
|
51
|
+
@staticmethod
|
|
52
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
53
|
+
return b"test"
|
|
54
|
+
|
|
55
|
+
instance = ValidSerialiser()
|
|
56
|
+
assert isinstance(instance, SerialiserLike)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_valid_implementation_with_classmethod():
|
|
60
|
+
"""测试使用 classmethod 的有效实现"""
|
|
61
|
+
|
|
62
|
+
class ValidSerialiser:
|
|
63
|
+
@classmethod
|
|
64
|
+
def serialise(cls, data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
65
|
+
return b"test"
|
|
66
|
+
|
|
67
|
+
instance = ValidSerialiser()
|
|
68
|
+
assert isinstance(instance, SerialiserLike)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_valid_implementation_with_instance_method():
|
|
72
|
+
"""测试使用实例方法的有效实现"""
|
|
73
|
+
|
|
74
|
+
class ValidSerialiser:
|
|
75
|
+
def serialise(self, data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
76
|
+
return b"test"
|
|
77
|
+
|
|
78
|
+
instance = ValidSerialiser()
|
|
79
|
+
assert isinstance(instance, SerialiserLike)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_valid_implementation_can_call_serialise():
|
|
83
|
+
"""测试有效实现可以调用 serialise"""
|
|
84
|
+
|
|
85
|
+
class ValidSerialiser:
|
|
86
|
+
@staticmethod
|
|
87
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
88
|
+
return b"serialized"
|
|
89
|
+
|
|
90
|
+
serialiser = ValidSerialiser()
|
|
91
|
+
result = serialiser.serialise({}, DataFormat.JSON)
|
|
92
|
+
assert result == b"serialized"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_valid_implementation_with_kwargs():
|
|
96
|
+
"""测试有效实现支持 kwargs"""
|
|
97
|
+
|
|
98
|
+
class ValidSerialiser:
|
|
99
|
+
@staticmethod
|
|
100
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
101
|
+
encoding = kwargs.get("encoding", "utf-8")
|
|
102
|
+
return f"encoded:{encoding}".encode()
|
|
103
|
+
|
|
104
|
+
serialiser = ValidSerialiser()
|
|
105
|
+
result = serialiser.serialise({}, DataFormat.JSON, encoding="ascii")
|
|
106
|
+
assert result == b"encoded:ascii"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_valid_implementation_with_complex_logic():
|
|
110
|
+
"""测试有效实现包含复杂逻辑"""
|
|
111
|
+
|
|
112
|
+
class ComplexSerialiser:
|
|
113
|
+
@staticmethod
|
|
114
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
115
|
+
if format == DataFormat.JSON:
|
|
116
|
+
import json
|
|
117
|
+
|
|
118
|
+
return json.dumps(data).encode()
|
|
119
|
+
elif format == DataFormat.CSV:
|
|
120
|
+
return b"csv,data"
|
|
121
|
+
else:
|
|
122
|
+
return b"unknown"
|
|
123
|
+
|
|
124
|
+
serialiser = ComplexSerialiser()
|
|
125
|
+
assert isinstance(serialiser, SerialiserLike)
|
|
126
|
+
result = serialiser.serialise({"key": "value"}, DataFormat.JSON)
|
|
127
|
+
assert result == b'{"key": "value"}'
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# =============================================================================
|
|
131
|
+
# Implementation Tests - Invalid Implementations
|
|
132
|
+
# =============================================================================
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_invalid_implementation_missing_method():
|
|
136
|
+
"""测试缺少 serialise 方法的实现"""
|
|
137
|
+
|
|
138
|
+
class InvalidSerialiser:
|
|
139
|
+
pass
|
|
140
|
+
|
|
141
|
+
instance = InvalidSerialiser()
|
|
142
|
+
assert not isinstance(instance, SerialiserLike)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def test_invalid_implementation_wrong_method_name():
|
|
146
|
+
"""测试方法名错误的实现"""
|
|
147
|
+
|
|
148
|
+
class InvalidSerialiser:
|
|
149
|
+
@staticmethod
|
|
150
|
+
def serialize(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
151
|
+
return b"test"
|
|
152
|
+
|
|
153
|
+
instance = InvalidSerialiser()
|
|
154
|
+
assert not isinstance(instance, SerialiserLike)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def test_property_implementation_is_valid():
|
|
158
|
+
"""测试使用 property 的实现也是有效的"""
|
|
159
|
+
|
|
160
|
+
class PropertySerialiser:
|
|
161
|
+
@property
|
|
162
|
+
def serialise(self):
|
|
163
|
+
return lambda data, format, **kwargs: b"test"
|
|
164
|
+
|
|
165
|
+
instance = PropertySerialiser()
|
|
166
|
+
# Python's Protocol accepts properties with callable values
|
|
167
|
+
assert isinstance(instance, SerialiserLike)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
# =============================================================================
|
|
171
|
+
# Type Checking Tests
|
|
172
|
+
# =============================================================================
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_isinstance_with_valid_class():
|
|
176
|
+
"""测试 isinstance 检查有效类"""
|
|
177
|
+
|
|
178
|
+
class MySerialiser:
|
|
179
|
+
@staticmethod
|
|
180
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
181
|
+
return b""
|
|
182
|
+
|
|
183
|
+
assert isinstance(MySerialiser(), SerialiserLike)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def test_isinstance_with_invalid_class():
|
|
187
|
+
"""测试 isinstance 检查无效类"""
|
|
188
|
+
|
|
189
|
+
class NotSerialiser:
|
|
190
|
+
def other_method(self):
|
|
191
|
+
pass
|
|
192
|
+
|
|
193
|
+
assert not isinstance(NotSerialiser(), SerialiserLike)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def test_isinstance_with_builtin_types():
|
|
197
|
+
"""测试 isinstance 检查内置类型"""
|
|
198
|
+
assert not isinstance(str(), SerialiserLike)
|
|
199
|
+
assert not isinstance(int(), SerialiserLike)
|
|
200
|
+
assert not isinstance(list(), SerialiserLike)
|
|
201
|
+
assert not isinstance(dict(), SerialiserLike)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def test_isinstance_with_none():
|
|
205
|
+
"""测试 isinstance 检查 None"""
|
|
206
|
+
assert not isinstance(None, SerialiserLike)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# =============================================================================
|
|
210
|
+
# Inheritance Tests
|
|
211
|
+
# =============================================================================
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def test_can_inherit_from_protocol():
|
|
215
|
+
"""测试可以继承协议"""
|
|
216
|
+
|
|
217
|
+
class BaseSerialiser(SerialiserLike):
|
|
218
|
+
@staticmethod
|
|
219
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
220
|
+
return b"base"
|
|
221
|
+
|
|
222
|
+
instance = BaseSerialiser()
|
|
223
|
+
assert isinstance(instance, SerialiserLike)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def test_inherited_class_can_override():
|
|
227
|
+
"""测试继承类可以重写方法"""
|
|
228
|
+
|
|
229
|
+
class BaseSerialiser(SerialiserLike):
|
|
230
|
+
@staticmethod
|
|
231
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
232
|
+
return b"base"
|
|
233
|
+
|
|
234
|
+
class DerivedSerialiser(BaseSerialiser):
|
|
235
|
+
@staticmethod
|
|
236
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
237
|
+
return b"derived"
|
|
238
|
+
|
|
239
|
+
derived = DerivedSerialiser()
|
|
240
|
+
assert isinstance(derived, SerialiserLike)
|
|
241
|
+
assert derived.serialise({}, DataFormat.JSON) == b"derived"
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
# =============================================================================
|
|
245
|
+
# Edge Cases Tests
|
|
246
|
+
# =============================================================================
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def test_implementation_with_default_arguments():
|
|
250
|
+
"""测试带默认参数的实现"""
|
|
251
|
+
|
|
252
|
+
class SerialiserWithDefaults:
|
|
253
|
+
@staticmethod
|
|
254
|
+
def serialise(data: Any, format: Any = DataFormat.JSON, **kwargs: Any) -> bytes:
|
|
255
|
+
return b"default"
|
|
256
|
+
|
|
257
|
+
serialiser = SerialiserWithDefaults()
|
|
258
|
+
assert isinstance(serialiser, SerialiserLike)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def test_implementation_with_extra_methods():
|
|
262
|
+
"""测试包含额外方法的实现"""
|
|
263
|
+
|
|
264
|
+
class RichSerialiser:
|
|
265
|
+
@staticmethod
|
|
266
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
267
|
+
return b"test"
|
|
268
|
+
|
|
269
|
+
@staticmethod
|
|
270
|
+
def validate(data: Any) -> bool:
|
|
271
|
+
return True
|
|
272
|
+
|
|
273
|
+
serialiser = RichSerialiser()
|
|
274
|
+
assert isinstance(serialiser, SerialiserLike)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def test_implementation_with_attributes():
|
|
278
|
+
"""测试包含属性的实现"""
|
|
279
|
+
|
|
280
|
+
class SerialiserWithState:
|
|
281
|
+
def __init__(self):
|
|
282
|
+
self.counter = 0
|
|
283
|
+
|
|
284
|
+
def serialise(self, data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
285
|
+
self.counter += 1
|
|
286
|
+
return b"test"
|
|
287
|
+
|
|
288
|
+
serialiser = SerialiserWithState()
|
|
289
|
+
assert isinstance(serialiser, SerialiserLike)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def test_callable_object_as_implementation():
|
|
293
|
+
"""测试可调用对象作为实现"""
|
|
294
|
+
|
|
295
|
+
class CallableSerialiser:
|
|
296
|
+
def serialise(self, data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
297
|
+
return b"callable"
|
|
298
|
+
|
|
299
|
+
instance = CallableSerialiser()
|
|
300
|
+
assert isinstance(instance, SerialiserLike)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
# =============================================================================
|
|
304
|
+
# Real-World Usage Tests
|
|
305
|
+
# =============================================================================
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def test_parquet_serialiser_implementation():
|
|
309
|
+
"""测试 Parquet 序列化器实现"""
|
|
310
|
+
|
|
311
|
+
class ParquetSerialiser:
|
|
312
|
+
@staticmethod
|
|
313
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
314
|
+
if format != DataFormat.PARQUET:
|
|
315
|
+
raise ValueError(f"Unsupported format: {format}")
|
|
316
|
+
# Simulate parquet serialization
|
|
317
|
+
return b"parquet_data"
|
|
318
|
+
|
|
319
|
+
serialiser = ParquetSerialiser()
|
|
320
|
+
assert isinstance(serialiser, SerialiserLike)
|
|
321
|
+
result = serialiser.serialise({}, DataFormat.PARQUET)
|
|
322
|
+
assert result == b"parquet_data"
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def test_csv_serialiser_implementation():
|
|
326
|
+
"""测试 CSV 序列化器实现"""
|
|
327
|
+
|
|
328
|
+
class CSVSerialiser:
|
|
329
|
+
@staticmethod
|
|
330
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
331
|
+
if format != DataFormat.CSV:
|
|
332
|
+
raise ValueError(f"Unsupported format: {format}")
|
|
333
|
+
# Simulate CSV serialization
|
|
334
|
+
return b"col1,col2\nval1,val2"
|
|
335
|
+
|
|
336
|
+
serialiser = CSVSerialiser()
|
|
337
|
+
assert isinstance(serialiser, SerialiserLike)
|
|
338
|
+
result = serialiser.serialise({}, DataFormat.CSV)
|
|
339
|
+
assert result == b"col1,col2\nval1,val2"
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def test_json_serialiser_implementation():
|
|
343
|
+
"""测试 JSON 序列化器实现"""
|
|
344
|
+
import json
|
|
345
|
+
|
|
346
|
+
class JSONSerialiser:
|
|
347
|
+
@staticmethod
|
|
348
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
349
|
+
if format != DataFormat.JSON:
|
|
350
|
+
raise ValueError(f"Unsupported format: {format}")
|
|
351
|
+
return json.dumps(data).encode("utf-8")
|
|
352
|
+
|
|
353
|
+
serialiser = JSONSerialiser()
|
|
354
|
+
assert isinstance(serialiser, SerialiserLike)
|
|
355
|
+
result = serialiser.serialise({"test": 123}, DataFormat.JSON)
|
|
356
|
+
assert result == b'{"test": 123}'
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def test_multi_format_serialiser():
|
|
360
|
+
"""测试多格式序列化器"""
|
|
361
|
+
import json
|
|
362
|
+
|
|
363
|
+
class MultiFormatSerialiser:
|
|
364
|
+
@staticmethod
|
|
365
|
+
def serialise(data: Any, format: Any, **kwargs: Any) -> bytes:
|
|
366
|
+
if format == DataFormat.JSON:
|
|
367
|
+
return json.dumps(data).encode("utf-8")
|
|
368
|
+
elif format == DataFormat.CSV:
|
|
369
|
+
return b"csv_data"
|
|
370
|
+
elif format == DataFormat.PARQUET:
|
|
371
|
+
return b"parquet_data"
|
|
372
|
+
else:
|
|
373
|
+
raise ValueError(f"Unsupported format: {format}")
|
|
374
|
+
|
|
375
|
+
serialiser = MultiFormatSerialiser()
|
|
376
|
+
assert isinstance(serialiser, SerialiserLike)
|
|
377
|
+
|
|
378
|
+
# Test each format
|
|
379
|
+
json_result = serialiser.serialise({"key": "value"}, DataFormat.JSON)
|
|
380
|
+
assert json_result == b'{"key": "value"}'
|
|
381
|
+
|
|
382
|
+
csv_result = serialiser.serialise({}, DataFormat.CSV)
|
|
383
|
+
assert csv_result == b"csv_data"
|
|
384
|
+
|
|
385
|
+
parquet_result = serialiser.serialise({}, DataFormat.PARQUET)
|
|
386
|
+
assert parquet_result == b"parquet_data"
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
# =============================================================================
|
|
390
|
+
# Protocol Attribute Tests
|
|
391
|
+
# =============================================================================
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def test_protocol_module():
|
|
395
|
+
"""测试协议所属模块"""
|
|
396
|
+
assert SerialiserLike.__module__ == "xfintech.serde.common.serialiserlike"
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def test_protocol_name():
|
|
400
|
+
"""测试协议名称"""
|
|
401
|
+
assert SerialiserLike.__name__ == "SerialiserLike"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from io import BytesIO, StringIO
|
|
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.deserialiserlike import DeserialiserLike
|
|
10
|
+
from xfintech.serde.common.error import (
|
|
11
|
+
DeserialiserFailedError,
|
|
12
|
+
DeserialiserImportError,
|
|
13
|
+
DeserialiserInputTypeError,
|
|
14
|
+
DeserialiserNotSupportedError,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PandasDeserialiser(DeserialiserLike):
|
|
19
|
+
"""
|
|
20
|
+
描述:
|
|
21
|
+
- PandasDeserialiser反序列化模块。
|
|
22
|
+
- BYTES -> DataFrame 的转换,支持多种常见数据格式(Parquet、CSV、JSON)。
|
|
23
|
+
|
|
24
|
+
方法:
|
|
25
|
+
- deserialise(data, format, **kwargs): 通用反序列化方法,支持多种格式。
|
|
26
|
+
- from_parquet(data, **kwargs): 从 Parquet 格式的字节流反序列化为 DataFrame。
|
|
27
|
+
- from_csv(data, **kwargs): 从 CSV 格式的字节流反序列化为 DataFrame。
|
|
28
|
+
- from_json(data, **kwargs): 从 JSON 格式的字节流反序列化为 DataFrame。
|
|
29
|
+
|
|
30
|
+
例子:
|
|
31
|
+
```python
|
|
32
|
+
from xfintech.serde.deserialiser.pandas import PandasDeserialiser
|
|
33
|
+
from xfintech.serde.common.dataformat import DataFormat
|
|
34
|
+
|
|
35
|
+
# 使用通用反序列化方法(推荐)
|
|
36
|
+
df = PandasDeserialiser.deserialise(
|
|
37
|
+
bytes,
|
|
38
|
+
format=DataFormat.PARQUET,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def deserialise(
|
|
46
|
+
data: bytes,
|
|
47
|
+
format: DataFormat | str,
|
|
48
|
+
**kwargs: Any,
|
|
49
|
+
) -> pd.DataFrame:
|
|
50
|
+
if not isinstance(data, bytes):
|
|
51
|
+
msg = f"PandasDeserialiser.deserialise expects bytes, got {type(data)}"
|
|
52
|
+
raise DeserialiserInputTypeError(msg)
|
|
53
|
+
|
|
54
|
+
format = DataFormat.from_any(format)
|
|
55
|
+
if format == DataFormat.PARQUET:
|
|
56
|
+
return PandasDeserialiser.from_parquet(data, **kwargs)
|
|
57
|
+
elif format == DataFormat.CSV:
|
|
58
|
+
return PandasDeserialiser.from_csv(data, **kwargs)
|
|
59
|
+
elif format == DataFormat.JSON:
|
|
60
|
+
return PandasDeserialiser.from_json(data, **kwargs)
|
|
61
|
+
else:
|
|
62
|
+
msg = f"Unsupported DataFormat for deserialization: {format}"
|
|
63
|
+
raise DeserialiserNotSupportedError(msg)
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def from_parquet(
|
|
67
|
+
data: bytes,
|
|
68
|
+
**kwargs: Any,
|
|
69
|
+
) -> pd.DataFrame:
|
|
70
|
+
buffer = BytesIO(data)
|
|
71
|
+
try:
|
|
72
|
+
output = pd.read_parquet(buffer, **kwargs)
|
|
73
|
+
return output
|
|
74
|
+
except ImportError as e:
|
|
75
|
+
msg = "pyarrow is required for parquet deserialization. install via 'pip install pyarrow'."
|
|
76
|
+
raise DeserialiserImportError(msg) from e
|
|
77
|
+
except Exception as e:
|
|
78
|
+
msg = f"Failed to deserialize data: {e}"
|
|
79
|
+
raise DeserialiserFailedError(msg) from e
|
|
80
|
+
|
|
81
|
+
@staticmethod
|
|
82
|
+
def from_csv(
|
|
83
|
+
data: bytes,
|
|
84
|
+
**kwargs: Any,
|
|
85
|
+
) -> pd.DataFrame:
|
|
86
|
+
encoding = kwargs.pop("encoding", "utf-8")
|
|
87
|
+
try:
|
|
88
|
+
buffer = StringIO(data.decode(encoding))
|
|
89
|
+
return pd.read_csv(buffer, **kwargs)
|
|
90
|
+
except Exception as e:
|
|
91
|
+
msg = f"Failed to deserialize data: {e}"
|
|
92
|
+
raise DeserialiserFailedError(msg) from e
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def from_json(
|
|
96
|
+
data: bytes,
|
|
97
|
+
**kwargs: Any,
|
|
98
|
+
) -> pd.DataFrame:
|
|
99
|
+
encoding = kwargs.pop("encoding", "utf-8")
|
|
100
|
+
orient = kwargs.pop("orient", "records")
|
|
101
|
+
lines = kwargs.pop("lines", False)
|
|
102
|
+
try:
|
|
103
|
+
text = data.decode(encoding)
|
|
104
|
+
buf = StringIO(text)
|
|
105
|
+
return pd.read_json(
|
|
106
|
+
buf,
|
|
107
|
+
orient=orient,
|
|
108
|
+
lines=lines,
|
|
109
|
+
**kwargs,
|
|
110
|
+
)
|
|
111
|
+
except Exception as e:
|
|
112
|
+
msg = f"Failed to deserialize data: {e}"
|
|
113
|
+
raise DeserialiserFailedError(msg) from e
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from xfintech.serde.common.dataformat import DataFormat
|
|
7
|
+
from xfintech.serde.common.deserialiserlike import DeserialiserLike
|
|
8
|
+
from xfintech.serde.common.error import (
|
|
9
|
+
DeserialiserFailedError,
|
|
10
|
+
DeserialiserInputTypeError,
|
|
11
|
+
DeserialiserNotSupportedError,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PythonDeserialiser(DeserialiserLike):
|
|
16
|
+
"""
|
|
17
|
+
描述:
|
|
18
|
+
- PythonDict反序列化模块。
|
|
19
|
+
- BYTES -> DICT 的单向转换,适用于配置和轻量级数据交换。
|
|
20
|
+
|
|
21
|
+
方法:
|
|
22
|
+
- deserialise(data, format, **kwargs): 通用反序列化方法,仅支持 JSON 格式。
|
|
23
|
+
- from_json(data, **kwargs): 从 JSON 字节流解码为数据,编码默认 "utf-8"。
|
|
24
|
+
|
|
25
|
+
例子:
|
|
26
|
+
```python
|
|
27
|
+
from xfintech.serde.deserialiser.python import PythonDeserialiser
|
|
28
|
+
from xfintech.serde.common.dataformat import DataFormat
|
|
29
|
+
|
|
30
|
+
# 使用通用反序列化方法(推荐)
|
|
31
|
+
data = PythonDeserialiser.deserialise(
|
|
32
|
+
json_bytes,
|
|
33
|
+
format=DataFormat.JSON,
|
|
34
|
+
)
|
|
35
|
+
```
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def deserialise(
|
|
40
|
+
data: bytes,
|
|
41
|
+
format: DataFormat | str,
|
|
42
|
+
**kwargs: Any,
|
|
43
|
+
) -> Any:
|
|
44
|
+
if not isinstance(data, bytes):
|
|
45
|
+
msg = f"PythonDeserialiser.deserialise expects bytes, got {type(data)}"
|
|
46
|
+
raise DeserialiserInputTypeError(msg)
|
|
47
|
+
format = DataFormat.from_any(format)
|
|
48
|
+
if format == DataFormat.JSON:
|
|
49
|
+
return PythonDeserialiser.from_json(data, **kwargs)
|
|
50
|
+
else:
|
|
51
|
+
msg = f"Unsupported DataFormat for deserialization: {format}"
|
|
52
|
+
raise DeserialiserNotSupportedError(msg)
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def from_json(
|
|
56
|
+
data: bytes,
|
|
57
|
+
**kwargs: Any,
|
|
58
|
+
) -> Any:
|
|
59
|
+
encoding = kwargs.pop("encoding", "utf-8")
|
|
60
|
+
payload = data.decode(encoding)
|
|
61
|
+
try:
|
|
62
|
+
return json.loads(
|
|
63
|
+
payload,
|
|
64
|
+
**kwargs,
|
|
65
|
+
)
|
|
66
|
+
except Exception as e:
|
|
67
|
+
msg = f"Failed to deserialize data: {e}"
|
|
68
|
+
raise DeserialiserFailedError(msg) from e
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Tests for deserialiser modules
|