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,500 @@
|
|
|
1
|
+
"""
|
|
2
|
+
描述:
|
|
3
|
+
- DeserialiserLike 协议的单元测试。
|
|
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.deserialiserlike import DeserialiserLike
|
|
13
|
+
|
|
14
|
+
# =============================================================================
|
|
15
|
+
# Protocol Structure Tests
|
|
16
|
+
# =============================================================================
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_deserialiserlike_is_protocol():
|
|
20
|
+
"""测试 DeserialiserLike 是一个协议类"""
|
|
21
|
+
from typing import Protocol
|
|
22
|
+
|
|
23
|
+
assert issubclass(DeserialiserLike.__class__, type(Protocol))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_deserialiserlike_has_deserialise_method():
|
|
27
|
+
"""测试 DeserialiserLike 定义了 deserialise 方法"""
|
|
28
|
+
assert hasattr(DeserialiserLike, "deserialise")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_deserialiserlike_method_signature():
|
|
32
|
+
"""测试 deserialise 方法签名"""
|
|
33
|
+
import inspect
|
|
34
|
+
|
|
35
|
+
sig = inspect.signature(DeserialiserLike.deserialise)
|
|
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 ValidDeserialiser:
|
|
51
|
+
@staticmethod
|
|
52
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
53
|
+
return {"result": "test"}
|
|
54
|
+
|
|
55
|
+
instance = ValidDeserialiser()
|
|
56
|
+
assert isinstance(instance, DeserialiserLike)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_valid_implementation_with_classmethod():
|
|
60
|
+
"""测试使用 classmethod 的有效实现"""
|
|
61
|
+
|
|
62
|
+
class ValidDeserialiser:
|
|
63
|
+
@classmethod
|
|
64
|
+
def deserialise(cls, data: Any, format: Any, **kwargs: Any) -> Any:
|
|
65
|
+
return {"result": "test"}
|
|
66
|
+
|
|
67
|
+
instance = ValidDeserialiser()
|
|
68
|
+
assert isinstance(instance, DeserialiserLike)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_valid_implementation_with_instance_method():
|
|
72
|
+
"""测试使用实例方法的有效实现"""
|
|
73
|
+
|
|
74
|
+
class ValidDeserialiser:
|
|
75
|
+
def deserialise(self, data: Any, format: Any, **kwargs: Any) -> Any:
|
|
76
|
+
return {"result": "test"}
|
|
77
|
+
|
|
78
|
+
instance = ValidDeserialiser()
|
|
79
|
+
assert isinstance(instance, DeserialiserLike)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_valid_implementation_can_call_deserialise():
|
|
83
|
+
"""测试有效实现可以调用 deserialise"""
|
|
84
|
+
|
|
85
|
+
class ValidDeserialiser:
|
|
86
|
+
@staticmethod
|
|
87
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
88
|
+
return {"deserialised": True}
|
|
89
|
+
|
|
90
|
+
deserialiser = ValidDeserialiser()
|
|
91
|
+
result = deserialiser.deserialise(b"data", DataFormat.JSON)
|
|
92
|
+
assert result == {"deserialised": True}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_valid_implementation_with_kwargs():
|
|
96
|
+
"""测试有效实现支持 kwargs"""
|
|
97
|
+
|
|
98
|
+
class ValidDeserialiser:
|
|
99
|
+
@staticmethod
|
|
100
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
101
|
+
encoding = kwargs.get("encoding", "utf-8")
|
|
102
|
+
return {"encoding": encoding}
|
|
103
|
+
|
|
104
|
+
deserialiser = ValidDeserialiser()
|
|
105
|
+
result = deserialiser.deserialise(b"data", DataFormat.JSON, encoding="ascii")
|
|
106
|
+
assert result == {"encoding": "ascii"}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_valid_implementation_with_complex_logic():
|
|
110
|
+
"""测试有效实现包含复杂逻辑"""
|
|
111
|
+
import json
|
|
112
|
+
|
|
113
|
+
class ComplexDeserialiser:
|
|
114
|
+
@staticmethod
|
|
115
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
116
|
+
if format == DataFormat.JSON:
|
|
117
|
+
return json.loads(data)
|
|
118
|
+
elif format == DataFormat.CSV:
|
|
119
|
+
return {"type": "csv"}
|
|
120
|
+
else:
|
|
121
|
+
return {"type": "unknown"}
|
|
122
|
+
|
|
123
|
+
deserialiser = ComplexDeserialiser()
|
|
124
|
+
assert isinstance(deserialiser, DeserialiserLike)
|
|
125
|
+
result = deserialiser.deserialise(b'{"key": "value"}', DataFormat.JSON)
|
|
126
|
+
assert result == {"key": "value"}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# =============================================================================
|
|
130
|
+
# Implementation Tests - Invalid Implementations
|
|
131
|
+
# =============================================================================
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_invalid_implementation_missing_method():
|
|
135
|
+
"""测试缺少 deserialise 方法的实现"""
|
|
136
|
+
|
|
137
|
+
class InvalidDeserialiser:
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
instance = InvalidDeserialiser()
|
|
141
|
+
assert not isinstance(instance, DeserialiserLike)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_invalid_implementation_wrong_method_name():
|
|
145
|
+
"""测试方法名错误的实现"""
|
|
146
|
+
|
|
147
|
+
class InvalidDeserialiser:
|
|
148
|
+
@staticmethod
|
|
149
|
+
def deserialize(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
150
|
+
return {}
|
|
151
|
+
|
|
152
|
+
instance = InvalidDeserialiser()
|
|
153
|
+
assert not isinstance(instance, DeserialiserLike)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_property_implementation_is_valid():
|
|
157
|
+
"""测试使用 property 的实现也是有效的"""
|
|
158
|
+
|
|
159
|
+
class PropertyDeserialiser:
|
|
160
|
+
@property
|
|
161
|
+
def deserialise(self):
|
|
162
|
+
return lambda data, format, **kwargs: {}
|
|
163
|
+
|
|
164
|
+
instance = PropertyDeserialiser()
|
|
165
|
+
# Python's Protocol accepts properties with callable values
|
|
166
|
+
assert isinstance(instance, DeserialiserLike)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# =============================================================================
|
|
170
|
+
# Type Checking Tests
|
|
171
|
+
# =============================================================================
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def test_isinstance_with_valid_class():
|
|
175
|
+
"""测试 isinstance 检查有效类"""
|
|
176
|
+
|
|
177
|
+
class MyDeserialiser:
|
|
178
|
+
@staticmethod
|
|
179
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
180
|
+
return {}
|
|
181
|
+
|
|
182
|
+
assert isinstance(MyDeserialiser(), DeserialiserLike)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def test_isinstance_with_invalid_class():
|
|
186
|
+
"""测试 isinstance 检查无效类"""
|
|
187
|
+
|
|
188
|
+
class NotDeserialiser:
|
|
189
|
+
def other_method(self):
|
|
190
|
+
pass
|
|
191
|
+
|
|
192
|
+
assert not isinstance(NotDeserialiser(), DeserialiserLike)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def test_isinstance_with_builtin_types():
|
|
196
|
+
"""测试 isinstance 检查内置类型"""
|
|
197
|
+
assert not isinstance(str(), DeserialiserLike)
|
|
198
|
+
assert not isinstance(int(), DeserialiserLike)
|
|
199
|
+
assert not isinstance(list(), DeserialiserLike)
|
|
200
|
+
assert not isinstance(dict(), DeserialiserLike)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def test_isinstance_with_none():
|
|
204
|
+
"""测试 isinstance 检查 None"""
|
|
205
|
+
assert not isinstance(None, DeserialiserLike)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
# =============================================================================
|
|
209
|
+
# Inheritance Tests
|
|
210
|
+
# =============================================================================
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def test_can_inherit_from_protocol():
|
|
214
|
+
"""测试可以继承协议"""
|
|
215
|
+
|
|
216
|
+
class BaseDeserialiser(DeserialiserLike):
|
|
217
|
+
@staticmethod
|
|
218
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
219
|
+
return {"base": True}
|
|
220
|
+
|
|
221
|
+
instance = BaseDeserialiser()
|
|
222
|
+
assert isinstance(instance, DeserialiserLike)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def test_inherited_class_can_override():
|
|
226
|
+
"""测试继承类可以重写方法"""
|
|
227
|
+
|
|
228
|
+
class BaseDeserialiser(DeserialiserLike):
|
|
229
|
+
@staticmethod
|
|
230
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
231
|
+
return {"base": True}
|
|
232
|
+
|
|
233
|
+
class DerivedDeserialiser(BaseDeserialiser):
|
|
234
|
+
@staticmethod
|
|
235
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
236
|
+
return {"derived": True}
|
|
237
|
+
|
|
238
|
+
derived = DerivedDeserialiser()
|
|
239
|
+
assert isinstance(derived, DeserialiserLike)
|
|
240
|
+
assert derived.deserialise(b"", DataFormat.JSON) == {"derived": True}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
# =============================================================================
|
|
244
|
+
# Return Type Tests
|
|
245
|
+
# =============================================================================
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def test_can_return_dict():
|
|
249
|
+
"""测试可以返回字典"""
|
|
250
|
+
|
|
251
|
+
class DictDeserialiser:
|
|
252
|
+
@staticmethod
|
|
253
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
254
|
+
return {"key": "value"}
|
|
255
|
+
|
|
256
|
+
deserialiser = DictDeserialiser()
|
|
257
|
+
result = deserialiser.deserialise(b"", DataFormat.JSON)
|
|
258
|
+
assert isinstance(result, dict)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def test_can_return_dataframe():
|
|
262
|
+
"""测试可以返回 DataFrame(模拟)"""
|
|
263
|
+
|
|
264
|
+
class DataFrameDeserialiser:
|
|
265
|
+
@staticmethod
|
|
266
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
267
|
+
# Return a mock DataFrame-like object
|
|
268
|
+
class MockDataFrame:
|
|
269
|
+
pass
|
|
270
|
+
|
|
271
|
+
return MockDataFrame()
|
|
272
|
+
|
|
273
|
+
deserialiser = DataFrameDeserialiser()
|
|
274
|
+
assert isinstance(deserialiser, DeserialiserLike)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def test_can_return_list():
|
|
278
|
+
"""测试可以返回列表"""
|
|
279
|
+
|
|
280
|
+
class ListDeserialiser:
|
|
281
|
+
@staticmethod
|
|
282
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
283
|
+
return [1, 2, 3]
|
|
284
|
+
|
|
285
|
+
deserialiser = ListDeserialiser()
|
|
286
|
+
result = deserialiser.deserialise(b"", DataFormat.CSV)
|
|
287
|
+
assert isinstance(result, list)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def test_can_return_none():
|
|
291
|
+
"""测试可以返回 None"""
|
|
292
|
+
|
|
293
|
+
class NoneDeserialiser:
|
|
294
|
+
@staticmethod
|
|
295
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
296
|
+
return None
|
|
297
|
+
|
|
298
|
+
deserialiser = NoneDeserialiser()
|
|
299
|
+
result = deserialiser.deserialise(b"", DataFormat.JSON)
|
|
300
|
+
assert result is None
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
# =============================================================================
|
|
304
|
+
# Edge Cases Tests
|
|
305
|
+
# =============================================================================
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def test_implementation_with_default_arguments():
|
|
309
|
+
"""测试带默认参数的实现"""
|
|
310
|
+
|
|
311
|
+
class DeserialiserWithDefaults:
|
|
312
|
+
@staticmethod
|
|
313
|
+
def deserialise(data: Any, format: Any = DataFormat.JSON, **kwargs: Any) -> Any:
|
|
314
|
+
return {"default": True}
|
|
315
|
+
|
|
316
|
+
deserialiser = DeserialiserWithDefaults()
|
|
317
|
+
assert isinstance(deserialiser, DeserialiserLike)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def test_implementation_with_extra_methods():
|
|
321
|
+
"""测试包含额外方法的实现"""
|
|
322
|
+
|
|
323
|
+
class RichDeserialiser:
|
|
324
|
+
@staticmethod
|
|
325
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
326
|
+
return {}
|
|
327
|
+
|
|
328
|
+
@staticmethod
|
|
329
|
+
def validate(data: Any) -> bool:
|
|
330
|
+
return True
|
|
331
|
+
|
|
332
|
+
deserialiser = RichDeserialiser()
|
|
333
|
+
assert isinstance(deserialiser, DeserialiserLike)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def test_implementation_with_attributes():
|
|
337
|
+
"""测试包含属性的实现"""
|
|
338
|
+
|
|
339
|
+
class DeserialiserWithState:
|
|
340
|
+
def __init__(self):
|
|
341
|
+
self.counter = 0
|
|
342
|
+
|
|
343
|
+
def deserialise(self, data: Any, format: Any, **kwargs: Any) -> Any:
|
|
344
|
+
self.counter += 1
|
|
345
|
+
return {"count": self.counter}
|
|
346
|
+
|
|
347
|
+
deserialiser = DeserialiserWithState()
|
|
348
|
+
assert isinstance(deserialiser, DeserialiserLike)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def test_callable_object_as_implementation():
|
|
352
|
+
"""测试可调用对象作为实现"""
|
|
353
|
+
|
|
354
|
+
class CallableDeserialiser:
|
|
355
|
+
def deserialise(self, data: Any, format: Any, **kwargs: Any) -> Any:
|
|
356
|
+
return {"callable": True}
|
|
357
|
+
|
|
358
|
+
instance = CallableDeserialiser()
|
|
359
|
+
assert isinstance(instance, DeserialiserLike)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
# =============================================================================
|
|
363
|
+
# Real-World Usage Tests
|
|
364
|
+
# =============================================================================
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def test_parquet_deserialiser_implementation():
|
|
368
|
+
"""测试 Parquet 反序列化器实现"""
|
|
369
|
+
|
|
370
|
+
class ParquetDeserialiser:
|
|
371
|
+
@staticmethod
|
|
372
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
373
|
+
if format != DataFormat.PARQUET:
|
|
374
|
+
raise ValueError(f"Unsupported format: {format}")
|
|
375
|
+
# Simulate parquet deserialization
|
|
376
|
+
return {"parquet": "data"}
|
|
377
|
+
|
|
378
|
+
deserialiser = ParquetDeserialiser()
|
|
379
|
+
assert isinstance(deserialiser, DeserialiserLike)
|
|
380
|
+
result = deserialiser.deserialise(b"parquet_bytes", DataFormat.PARQUET)
|
|
381
|
+
assert result == {"parquet": "data"}
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def test_csv_deserialiser_implementation():
|
|
385
|
+
"""测试 CSV 反序列化器实现"""
|
|
386
|
+
|
|
387
|
+
class CSVDeserialiser:
|
|
388
|
+
@staticmethod
|
|
389
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
390
|
+
if format != DataFormat.CSV:
|
|
391
|
+
raise ValueError(f"Unsupported format: {format}")
|
|
392
|
+
# Simulate CSV deserialization
|
|
393
|
+
return [["col1", "col2"], ["val1", "val2"]]
|
|
394
|
+
|
|
395
|
+
deserialiser = CSVDeserialiser()
|
|
396
|
+
assert isinstance(deserialiser, DeserialiserLike)
|
|
397
|
+
result = deserialiser.deserialise(b"csv_bytes", DataFormat.CSV)
|
|
398
|
+
assert result == [["col1", "col2"], ["val1", "val2"]]
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def test_json_deserialiser_implementation():
|
|
402
|
+
"""测试 JSON 反序列化器实现"""
|
|
403
|
+
import json
|
|
404
|
+
|
|
405
|
+
class JSONDeserialiser:
|
|
406
|
+
@staticmethod
|
|
407
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
408
|
+
if format != DataFormat.JSON:
|
|
409
|
+
raise ValueError(f"Unsupported format: {format}")
|
|
410
|
+
if isinstance(data, bytes):
|
|
411
|
+
data = data.decode("utf-8")
|
|
412
|
+
return json.loads(data)
|
|
413
|
+
|
|
414
|
+
deserialiser = JSONDeserialiser()
|
|
415
|
+
assert isinstance(deserialiser, DeserialiserLike)
|
|
416
|
+
result = deserialiser.deserialise(b'{"test": 123}', DataFormat.JSON)
|
|
417
|
+
assert result == {"test": 123}
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def test_multi_format_deserialiser():
|
|
421
|
+
"""测试多格式反序列化器"""
|
|
422
|
+
import json
|
|
423
|
+
|
|
424
|
+
class MultiFormatDeserialiser:
|
|
425
|
+
@staticmethod
|
|
426
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
427
|
+
if format == DataFormat.JSON:
|
|
428
|
+
if isinstance(data, bytes):
|
|
429
|
+
data = data.decode("utf-8")
|
|
430
|
+
return json.loads(data)
|
|
431
|
+
elif format == DataFormat.CSV:
|
|
432
|
+
return {"type": "csv"}
|
|
433
|
+
elif format == DataFormat.PARQUET:
|
|
434
|
+
return {"type": "parquet"}
|
|
435
|
+
else:
|
|
436
|
+
raise ValueError(f"Unsupported format: {format}")
|
|
437
|
+
|
|
438
|
+
deserialiser = MultiFormatDeserialiser()
|
|
439
|
+
assert isinstance(deserialiser, DeserialiserLike)
|
|
440
|
+
|
|
441
|
+
# Test each format
|
|
442
|
+
json_result = deserialiser.deserialise(b'{"key": "value"}', DataFormat.JSON)
|
|
443
|
+
assert json_result == {"key": "value"}
|
|
444
|
+
|
|
445
|
+
csv_result = deserialiser.deserialise(b"csv_data", DataFormat.CSV)
|
|
446
|
+
assert csv_result == {"type": "csv"}
|
|
447
|
+
|
|
448
|
+
parquet_result = deserialiser.deserialise(b"parquet_data", DataFormat.PARQUET)
|
|
449
|
+
assert parquet_result == {"type": "parquet"}
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def test_deserialiser_with_encoding_option():
|
|
453
|
+
"""测试支持编码选项的反序列化器"""
|
|
454
|
+
|
|
455
|
+
class EncodingDeserialiser:
|
|
456
|
+
@staticmethod
|
|
457
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
458
|
+
encoding = kwargs.get("encoding", "utf-8")
|
|
459
|
+
if isinstance(data, bytes):
|
|
460
|
+
return data.decode(encoding)
|
|
461
|
+
return data
|
|
462
|
+
|
|
463
|
+
deserialiser = EncodingDeserialiser()
|
|
464
|
+
result = deserialiser.deserialise(b"test", DataFormat.CSV, encoding="utf-8")
|
|
465
|
+
assert result == "test"
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
def test_deserialiser_with_error_handling():
|
|
469
|
+
"""测试包含错误处理的反序列化器"""
|
|
470
|
+
|
|
471
|
+
class SafeDeserialiser:
|
|
472
|
+
@staticmethod
|
|
473
|
+
def deserialise(data: Any, format: Any, **kwargs: Any) -> Any:
|
|
474
|
+
try:
|
|
475
|
+
if format == DataFormat.JSON:
|
|
476
|
+
import json
|
|
477
|
+
|
|
478
|
+
return json.loads(data)
|
|
479
|
+
return None
|
|
480
|
+
except Exception:
|
|
481
|
+
return {"error": "deserialization failed"}
|
|
482
|
+
|
|
483
|
+
deserialiser = SafeDeserialiser()
|
|
484
|
+
result = deserialiser.deserialise(b"invalid json", DataFormat.JSON)
|
|
485
|
+
assert result == {"error": "deserialization failed"}
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
# =============================================================================
|
|
489
|
+
# Protocol Attribute Tests
|
|
490
|
+
# =============================================================================
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def test_protocol_module():
|
|
494
|
+
"""测试协议所属模块"""
|
|
495
|
+
assert DeserialiserLike.__module__ == "xfintech.serde.common.deserialiserlike"
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def test_protocol_name():
|
|
499
|
+
"""测试协议名称"""
|
|
500
|
+
assert DeserialiserLike.__name__ == "DeserialiserLike"
|