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,647 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from xfintech.data.source.tushare.stock.companyoverview import CompanyOverview
|
|
5
|
+
from xfintech.data.source.tushare.stock.companyoverview.constant import (
|
|
6
|
+
KEY,
|
|
7
|
+
NAME,
|
|
8
|
+
PAGINATE,
|
|
9
|
+
SOURCE,
|
|
10
|
+
TARGET,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
# Test Fixtures
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class FakeConnection:
|
|
17
|
+
"""Fake Tushare connection for testing"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, frame: pd.DataFrame):
|
|
20
|
+
self.frame = frame
|
|
21
|
+
|
|
22
|
+
def express_vip(self, **kwargs):
|
|
23
|
+
"""Mock express_vip API call"""
|
|
24
|
+
return self.frame
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FakeSession:
|
|
28
|
+
"""Fake session for testing"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, connection: FakeConnection):
|
|
31
|
+
self.connection = connection
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.fixture
|
|
35
|
+
def mock_session():
|
|
36
|
+
"""Create a mock session with empty data"""
|
|
37
|
+
fake_conn = FakeConnection(frame=pd.DataFrame())
|
|
38
|
+
return FakeSession(fake_conn)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.fixture
|
|
42
|
+
def sample_source_data():
|
|
43
|
+
"""Sample company overview data in Tushare format"""
|
|
44
|
+
return pd.DataFrame(
|
|
45
|
+
{
|
|
46
|
+
"ts_code": ["000001.SZ", "000001.SZ", "000002.SZ"],
|
|
47
|
+
"ann_date": ["20200430", "20201031", "20200430"],
|
|
48
|
+
"end_date": ["20200331", "20200930", "20200331"],
|
|
49
|
+
"revenue": ["100000000.50", "120000000.75", "50000000.25"],
|
|
50
|
+
"operate_profit": ["15000000.30", "18000000.40", "6000000.15"],
|
|
51
|
+
"total_profit": ["16000000.20", "19000000.35", "7000000.10"],
|
|
52
|
+
"n_income": ["12000000.00", "14000000.00", "5000000.00"],
|
|
53
|
+
"total_assets": ["500000000.50", "550000000.75", "200000000.25"],
|
|
54
|
+
"total_hldr_eqy_exc_min_int": ["200000000.50", "220000000.75", "80000000.25"],
|
|
55
|
+
"diluted_eps": ["0.50", "0.60", "0.25"],
|
|
56
|
+
"diluted_roe": ["8.5", "9.2", "7.3"],
|
|
57
|
+
"yoy_net_profit": ["10000000.00", "12000000.00", "4500000.00"],
|
|
58
|
+
"bps": ["5.5", "6.0", "4.2"],
|
|
59
|
+
"yoy_sales": ["15.5", "18.2", "12.3"],
|
|
60
|
+
"yoy_op": ["20.3", "22.5", "15.8"],
|
|
61
|
+
"yoy_tp": ["18.7", "20.9", "14.2"],
|
|
62
|
+
"yoy_dedu_np": ["16.5", "18.8", "13.5"],
|
|
63
|
+
"yoy_eps": ["15.0", "17.5", "12.0"],
|
|
64
|
+
"yoy_roe": ["1.5", "2.0", "1.0"],
|
|
65
|
+
"growth_assets": ["10.5", "12.3", "8.7"],
|
|
66
|
+
"yoy_equity": ["11.2", "13.5", "9.3"],
|
|
67
|
+
"growth_bps": ["12.0", "14.2", "10.1"],
|
|
68
|
+
"or_last_year": ["85000000.00", "100000000.00", "44000000.00"],
|
|
69
|
+
"op_last_year": ["12500000.00", "15000000.00", "5200000.00"],
|
|
70
|
+
"tp_last_year": ["13500000.00", "16000000.00", "6100000.00"],
|
|
71
|
+
"np_last_year": ["10300000.00", "12000000.00", "4400000.00"],
|
|
72
|
+
"eps_last_year": ["0.43", "0.51", "0.22"],
|
|
73
|
+
"open_net_assets": ["180000000.00", "200000000.00", "73000000.00"],
|
|
74
|
+
"open_bps": ["4.9", "5.4", "3.8"],
|
|
75
|
+
"perf_summary": ["业绩稳定增长", "持续盈利", "良好表现"],
|
|
76
|
+
"is_audit": ["1", "0", "1"],
|
|
77
|
+
"remark": ["", "预计数据", ""],
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# Initialization Tests
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_companyoverview_init_basic(mock_session):
|
|
86
|
+
"""Test basic initialization with required session"""
|
|
87
|
+
overview = CompanyOverview(session=mock_session)
|
|
88
|
+
assert overview.name == NAME
|
|
89
|
+
assert overview.key == KEY
|
|
90
|
+
assert overview.source == SOURCE
|
|
91
|
+
assert overview.target == TARGET
|
|
92
|
+
assert overview.paginate == PAGINATE
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_companyoverview_init_with_params_dict(mock_session):
|
|
96
|
+
"""Test initialization with params as dict"""
|
|
97
|
+
params = {"ts_code": "000001.SZ", "start_date": "20200101", "end_date": "20201231"}
|
|
98
|
+
overview = CompanyOverview(session=mock_session, params=params)
|
|
99
|
+
assert overview.params.get("ts_code") == "000001.SZ"
|
|
100
|
+
assert overview.params.get("start_date") == "20200101"
|
|
101
|
+
assert overview.params.get("end_date") == "20201231"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_companyoverview_init_with_params_object(mock_session):
|
|
105
|
+
"""Test initialization with params as Params object"""
|
|
106
|
+
from xfintech.data.common.params import Params
|
|
107
|
+
|
|
108
|
+
params = Params(ts_code="000001.SZ", start_date="20200101")
|
|
109
|
+
overview = CompanyOverview(session=mock_session, params=params)
|
|
110
|
+
assert overview.params.get("ts_code") == "000001.SZ"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_companyoverview_init_with_cache_bool_true(mock_session):
|
|
114
|
+
"""Test initialization with cache enabled"""
|
|
115
|
+
overview = CompanyOverview(session=mock_session, cache=True)
|
|
116
|
+
assert overview.cache is not None
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_companyoverview_init_with_cache_bool_false(mock_session):
|
|
120
|
+
"""Test initialization with cache disabled"""
|
|
121
|
+
overview = CompanyOverview(session=mock_session, cache=False)
|
|
122
|
+
assert overview.cache is None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_companyoverview_init_with_cache_dict(mock_session):
|
|
126
|
+
"""Test initialization with cache config dict"""
|
|
127
|
+
cache_config = {"path": "/tmp/cache", "key": "test"}
|
|
128
|
+
overview = CompanyOverview(session=mock_session, cache=cache_config)
|
|
129
|
+
assert overview.cache is not None
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_companyoverview_init_default_paginate_limit(mock_session):
|
|
133
|
+
"""Test that default pagination limit is set correctly"""
|
|
134
|
+
overview = CompanyOverview(session=mock_session)
|
|
135
|
+
assert overview.paginate.pagesize == 1000
|
|
136
|
+
assert overview.paginate.pagelimit == 1000
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def test_companyoverview_init_with_all_params(mock_session):
|
|
140
|
+
"""Test initialization with all parameters"""
|
|
141
|
+
params = {"ts_code": "000001.SZ", "start_date": "20200101", "end_date": "20201231"}
|
|
142
|
+
coolant = {"interval": 0.5}
|
|
143
|
+
retry = {"max_attempts": 3}
|
|
144
|
+
cache = True
|
|
145
|
+
|
|
146
|
+
overview = CompanyOverview(session=mock_session, params=params, coolant=coolant, retry=retry, cache=cache)
|
|
147
|
+
assert overview.params.get("ts_code") == "000001.SZ"
|
|
148
|
+
assert overview.cache is not None
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_companyoverview_constants():
|
|
152
|
+
"""Test that constants are correctly defined"""
|
|
153
|
+
assert NAME == "companyoverview"
|
|
154
|
+
assert KEY == "/tushare/companyoverview"
|
|
155
|
+
assert SOURCE.name == "express_vip"
|
|
156
|
+
assert TARGET.name == "companyoverview"
|
|
157
|
+
assert PAGINATE.pagesize == 1000
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# Transform Tests
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def test_companyoverview_transform_basic(sample_source_data):
|
|
164
|
+
"""Test basic transformation of overview data"""
|
|
165
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
166
|
+
session = FakeSession(fake_conn)
|
|
167
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
168
|
+
|
|
169
|
+
result = overview.transform(sample_source_data)
|
|
170
|
+
|
|
171
|
+
assert len(result) == 3
|
|
172
|
+
assert "code" in result.columns
|
|
173
|
+
assert "date" in result.columns
|
|
174
|
+
assert "datecode" in result.columns
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def test_companyoverview_transform_code_mapping(sample_source_data):
|
|
178
|
+
"""Test that ts_code is correctly mapped to code"""
|
|
179
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
180
|
+
session = FakeSession(fake_conn)
|
|
181
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
182
|
+
|
|
183
|
+
result = overview.transform(sample_source_data)
|
|
184
|
+
|
|
185
|
+
assert result.iloc[0]["code"] == "000001.SZ"
|
|
186
|
+
assert result.iloc[2]["code"] == "000002.SZ"
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def test_companyoverview_transform_date_format(sample_source_data):
|
|
190
|
+
"""Test that dates are properly formatted"""
|
|
191
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
192
|
+
session = FakeSession(fake_conn)
|
|
193
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
194
|
+
|
|
195
|
+
result = overview.transform(sample_source_data)
|
|
196
|
+
|
|
197
|
+
assert pd.api.types.is_datetime64_any_dtype(result["date"]) is False
|
|
198
|
+
assert result.iloc[0]["date"] == "2020-03-31"
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def test_companyoverview_transform_datecode_preserved(sample_source_data):
|
|
202
|
+
"""Test that datecode is correctly created from end_date"""
|
|
203
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
204
|
+
session = FakeSession(fake_conn)
|
|
205
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
206
|
+
|
|
207
|
+
result = overview.transform(sample_source_data)
|
|
208
|
+
|
|
209
|
+
assert result.iloc[0]["datecode"] == "20200331"
|
|
210
|
+
assert result.iloc[1]["datecode"] == "20200930"
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def test_companyoverview_transform_numeric_conversions(sample_source_data):
|
|
214
|
+
"""Test that numeric fields are properly converted"""
|
|
215
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
216
|
+
session = FakeSession(fake_conn)
|
|
217
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
218
|
+
|
|
219
|
+
result = overview.transform(sample_source_data)
|
|
220
|
+
|
|
221
|
+
assert result.iloc[0]["revenue"] == 100000000.50
|
|
222
|
+
assert result.iloc[0]["operate_profit"] == 15000000.30
|
|
223
|
+
assert pd.api.types.is_numeric_dtype(result["revenue"])
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def test_companyoverview_transform_string_fields(sample_source_data):
|
|
227
|
+
"""Test that string fields are properly converted"""
|
|
228
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
229
|
+
session = FakeSession(fake_conn)
|
|
230
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
231
|
+
|
|
232
|
+
result = overview.transform(sample_source_data)
|
|
233
|
+
|
|
234
|
+
assert result.iloc[0]["perf_summary"] == "业绩稳定增长"
|
|
235
|
+
assert result.iloc[1]["remark"] == "预计数据"
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def test_companyoverview_transform_empty_dataframe():
|
|
239
|
+
"""Test transformation with empty dataframe"""
|
|
240
|
+
fake_conn = FakeConnection(frame=pd.DataFrame())
|
|
241
|
+
session = FakeSession(fake_conn)
|
|
242
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
243
|
+
|
|
244
|
+
result = overview.transform(pd.DataFrame())
|
|
245
|
+
|
|
246
|
+
assert isinstance(result, pd.DataFrame)
|
|
247
|
+
assert result.empty
|
|
248
|
+
assert len(result.columns) == len(TARGET.list_column_names())
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def test_companyoverview_transform_none_input():
|
|
252
|
+
"""Test transformation with None input"""
|
|
253
|
+
fake_conn = FakeConnection(frame=pd.DataFrame())
|
|
254
|
+
session = FakeSession(fake_conn)
|
|
255
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
256
|
+
|
|
257
|
+
result = overview.transform(None)
|
|
258
|
+
|
|
259
|
+
assert isinstance(result, pd.DataFrame)
|
|
260
|
+
assert result.empty
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def test_companyoverview_transform_handles_invalid_dates():
|
|
264
|
+
"""Test that invalid dates are handled gracefully"""
|
|
265
|
+
data = pd.DataFrame(
|
|
266
|
+
{
|
|
267
|
+
"ts_code": ["000001.SZ"],
|
|
268
|
+
"ann_date": ["invalid"],
|
|
269
|
+
"end_date": ["20200331"],
|
|
270
|
+
"revenue": ["100000000.00"],
|
|
271
|
+
"is_audit": ["1"],
|
|
272
|
+
}
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
fake_conn = FakeConnection(frame=data)
|
|
276
|
+
session = FakeSession(fake_conn)
|
|
277
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
278
|
+
|
|
279
|
+
result = overview.transform(data)
|
|
280
|
+
|
|
281
|
+
assert len(result) == 1
|
|
282
|
+
assert pd.isna(result.iloc[0]["ann_date"])
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def test_companyoverview_transform_removes_duplicates(sample_source_data):
|
|
286
|
+
"""Test that duplicate rows are removed"""
|
|
287
|
+
# Create data with duplicates
|
|
288
|
+
data = pd.concat([sample_source_data, sample_source_data.iloc[[0]]], ignore_index=True)
|
|
289
|
+
|
|
290
|
+
fake_conn = FakeConnection(frame=data)
|
|
291
|
+
session = FakeSession(fake_conn)
|
|
292
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
293
|
+
|
|
294
|
+
result = overview.transform(data)
|
|
295
|
+
|
|
296
|
+
# Should have 3 unique rows, not 4
|
|
297
|
+
assert len(result) == 3
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def test_companyoverview_transform_sorts_by_code_and_date(sample_source_data):
|
|
301
|
+
"""Test that output is sorted by code and date"""
|
|
302
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
303
|
+
session = FakeSession(fake_conn)
|
|
304
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
305
|
+
|
|
306
|
+
result = overview.transform(sample_source_data)
|
|
307
|
+
|
|
308
|
+
# Check first row is 000001.SZ, 2020-03-31
|
|
309
|
+
assert result.iloc[0]["code"] == "000001.SZ"
|
|
310
|
+
assert result.iloc[0]["date"] == "2020-03-31"
|
|
311
|
+
# Check last row is 000002.SZ
|
|
312
|
+
assert result.iloc[2]["code"] == "000002.SZ"
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def test_companyoverview_transform_resets_index():
|
|
316
|
+
"""Test that index is reset after transformation"""
|
|
317
|
+
data = pd.DataFrame(
|
|
318
|
+
{
|
|
319
|
+
"ts_code": ["000001.SZ", "000002.SZ"],
|
|
320
|
+
"ann_date": ["20200430", "20200430"],
|
|
321
|
+
"end_date": ["20200331", "20200331"],
|
|
322
|
+
"revenue": ["100000000.00", "50000000.00"],
|
|
323
|
+
"is_audit": ["1", "1"],
|
|
324
|
+
},
|
|
325
|
+
index=[5, 10],
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
fake_conn = FakeConnection(frame=data)
|
|
329
|
+
session = FakeSession(fake_conn)
|
|
330
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
331
|
+
|
|
332
|
+
result = overview.transform(data)
|
|
333
|
+
|
|
334
|
+
assert result.index.tolist() == [0, 1]
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def test_companyoverview_transform_only_target_columns(sample_source_data):
|
|
338
|
+
"""Test that only target columns are in output"""
|
|
339
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
340
|
+
session = FakeSession(fake_conn)
|
|
341
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
342
|
+
|
|
343
|
+
result = overview.transform(sample_source_data)
|
|
344
|
+
|
|
345
|
+
expected_cols = set(TARGET.list_column_names())
|
|
346
|
+
actual_cols = set(result.columns)
|
|
347
|
+
|
|
348
|
+
assert actual_cols == expected_cols
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
# Run Method Tests
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def test_companyoverview_run_with_cache_hit(sample_source_data):
|
|
355
|
+
"""Test that run() returns cached data when available"""
|
|
356
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
357
|
+
session = FakeSession(fake_conn)
|
|
358
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"}, cache=True)
|
|
359
|
+
|
|
360
|
+
# First run should fetch and cache
|
|
361
|
+
result1 = overview.run()
|
|
362
|
+
|
|
363
|
+
# Second run should return cached data
|
|
364
|
+
result2 = overview.run()
|
|
365
|
+
|
|
366
|
+
pd.testing.assert_frame_equal(result1, result2)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def test_companyoverview_run_basic_date_range(sample_source_data):
|
|
370
|
+
"""Test run() with date range parameters"""
|
|
371
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
372
|
+
session = FakeSession(fake_conn)
|
|
373
|
+
overview = CompanyOverview(
|
|
374
|
+
session=session,
|
|
375
|
+
params={"ts_code": "000001.SZ", "start_date": "20200101", "end_date": "20201231"},
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
result = overview.run()
|
|
379
|
+
|
|
380
|
+
assert isinstance(result, pd.DataFrame)
|
|
381
|
+
assert len(result) > 0
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def test_companyoverview_run_with_period_param(sample_source_data):
|
|
385
|
+
"""Test run() with period parameter"""
|
|
386
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
387
|
+
session = FakeSession(fake_conn)
|
|
388
|
+
overview = CompanyOverview(
|
|
389
|
+
session=session,
|
|
390
|
+
params={"ts_code": "000001.SZ", "period": "2020-3"},
|
|
391
|
+
)
|
|
392
|
+
result = overview.run()
|
|
393
|
+
assert isinstance(result, pd.DataFrame)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def test_companyoverview_run_with_datetime_params(sample_source_data):
|
|
397
|
+
"""Test run() with datetime objects as parameters"""
|
|
398
|
+
from datetime import datetime
|
|
399
|
+
|
|
400
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
401
|
+
session = FakeSession(fake_conn)
|
|
402
|
+
overview = CompanyOverview(
|
|
403
|
+
session=session,
|
|
404
|
+
params={
|
|
405
|
+
"ts_code": "000001.SZ",
|
|
406
|
+
"start_date": datetime(2020, 1, 1),
|
|
407
|
+
"end_date": datetime(2020, 12, 31),
|
|
408
|
+
},
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
result = overview.run()
|
|
412
|
+
|
|
413
|
+
assert isinstance(result, pd.DataFrame)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def test_companyoverview_run_adds_fields_param(sample_source_data):
|
|
417
|
+
"""Test that run() adds fields parameter if not provided"""
|
|
418
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
419
|
+
session = FakeSession(fake_conn)
|
|
420
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
421
|
+
|
|
422
|
+
# Monkey patch _fetchall to capture params
|
|
423
|
+
overview._fetchall
|
|
424
|
+
captured_params = {}
|
|
425
|
+
|
|
426
|
+
def mock_fetchall(api, **kwargs):
|
|
427
|
+
captured_params.update(kwargs)
|
|
428
|
+
return sample_source_data
|
|
429
|
+
|
|
430
|
+
overview._fetchall = mock_fetchall
|
|
431
|
+
overview.run()
|
|
432
|
+
|
|
433
|
+
assert "fields" in captured_params
|
|
434
|
+
assert len(captured_params["fields"]) > 0
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def test_companyoverview_run_sets_cache(sample_source_data):
|
|
438
|
+
"""Test that run() saves result to cache"""
|
|
439
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
440
|
+
session = FakeSession(fake_conn)
|
|
441
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"}, cache=True)
|
|
442
|
+
|
|
443
|
+
result = overview.run()
|
|
444
|
+
|
|
445
|
+
# Cache should be set after run
|
|
446
|
+
cached = overview._load_cache()
|
|
447
|
+
assert cached is not None
|
|
448
|
+
pd.testing.assert_frame_equal(result, cached)
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def test_companyoverview_run_calls_transform(sample_source_data):
|
|
452
|
+
"""Test that run() calls transform method"""
|
|
453
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
454
|
+
session = FakeSession(fake_conn)
|
|
455
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
456
|
+
|
|
457
|
+
# Monkey patch transform to track if it was called
|
|
458
|
+
original_transform = overview.transform
|
|
459
|
+
transform_called = {"called": False}
|
|
460
|
+
|
|
461
|
+
def mock_transform(data):
|
|
462
|
+
transform_called["called"] = True
|
|
463
|
+
return original_transform(data)
|
|
464
|
+
|
|
465
|
+
overview.transform = mock_transform
|
|
466
|
+
overview.run()
|
|
467
|
+
|
|
468
|
+
assert transform_called["called"] is True
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def test_companyoverview_run_uses_express_vip_api(sample_source_data):
|
|
472
|
+
"""Test that run() uses express_vip API"""
|
|
473
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
474
|
+
session = FakeSession(fake_conn)
|
|
475
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
476
|
+
|
|
477
|
+
# Monkey patch _fetchall to capture API
|
|
478
|
+
captured_api = {"api": None}
|
|
479
|
+
|
|
480
|
+
def mock_fetchall(api, **kwargs):
|
|
481
|
+
captured_api["api"] = api
|
|
482
|
+
return sample_source_data
|
|
483
|
+
|
|
484
|
+
overview._fetchall = mock_fetchall
|
|
485
|
+
overview.run()
|
|
486
|
+
|
|
487
|
+
assert captured_api["api"] == session.connection.express_vip
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
# Integration Tests
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def test_companyoverview_full_workflow(sample_source_data):
|
|
494
|
+
"""Test complete workflow from initialization to output"""
|
|
495
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
496
|
+
session = FakeSession(fake_conn)
|
|
497
|
+
|
|
498
|
+
overview = CompanyOverview(
|
|
499
|
+
session=session,
|
|
500
|
+
params={"ts_code": "000001.SZ", "start_date": "20200101", "end_date": "20201231"},
|
|
501
|
+
cache=True,
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
result = overview.run()
|
|
505
|
+
|
|
506
|
+
# Verify output structure
|
|
507
|
+
assert isinstance(result, pd.DataFrame)
|
|
508
|
+
assert len(result) == 3
|
|
509
|
+
assert "code" in result.columns
|
|
510
|
+
assert "date" in result.columns
|
|
511
|
+
assert "revenue" in result.columns
|
|
512
|
+
assert "n_income" in result.columns
|
|
513
|
+
|
|
514
|
+
# Verify data types
|
|
515
|
+
assert pd.api.types.is_numeric_dtype(result["revenue"])
|
|
516
|
+
assert result.iloc[0]["code"] == "000001.SZ"
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
def test_companyoverview_cache_persistence(sample_source_data):
|
|
520
|
+
"""Test that cache persists across multiple runs"""
|
|
521
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
522
|
+
session = FakeSession(fake_conn)
|
|
523
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"}, cache=True)
|
|
524
|
+
|
|
525
|
+
# Run once to populate cache
|
|
526
|
+
result1 = overview.run()
|
|
527
|
+
|
|
528
|
+
# Clear in-memory data to simulate fresh load
|
|
529
|
+
overview2 = CompanyOverview(session=session, params={"ts_code": "000001.SZ"}, cache=True)
|
|
530
|
+
result2 = overview2.run()
|
|
531
|
+
|
|
532
|
+
pd.testing.assert_frame_equal(result1, result2)
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def test_companyoverview_params_uniqueness(mock_session):
|
|
536
|
+
"""Test that different params produce different cache keys"""
|
|
537
|
+
overview1 = CompanyOverview(
|
|
538
|
+
session=mock_session,
|
|
539
|
+
params={"ts_code": "000001.SZ", "start_date": "20200101"},
|
|
540
|
+
cache=True,
|
|
541
|
+
)
|
|
542
|
+
overview2 = CompanyOverview(
|
|
543
|
+
session=mock_session,
|
|
544
|
+
params={"ts_code": "000001.SZ", "start_date": "20210101"},
|
|
545
|
+
cache=True,
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
# Test that different params are properly stored
|
|
549
|
+
assert overview1.params.get("start_date") == "20200101"
|
|
550
|
+
assert overview2.params.get("start_date") == "20210101"
|
|
551
|
+
assert overview1.params.get("start_date") != overview2.params.get("start_date")
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
def test_companyoverview_different_stocks(sample_source_data):
|
|
555
|
+
"""Test that different stock codes are handled correctly"""
|
|
556
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
557
|
+
session = FakeSession(fake_conn)
|
|
558
|
+
|
|
559
|
+
overview1 = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
560
|
+
result1 = overview1.run()
|
|
561
|
+
|
|
562
|
+
overview2 = CompanyOverview(session=session, params={"ts_code": "000002.SZ"})
|
|
563
|
+
result2 = overview2.run()
|
|
564
|
+
|
|
565
|
+
# Both should have data for their respective stocks
|
|
566
|
+
assert "000001.SZ" in result1["code"].values
|
|
567
|
+
assert "000002.SZ" in result2["code"].values
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
def test_companyoverview_empty_result_handling():
|
|
571
|
+
"""Test handling of empty API results"""
|
|
572
|
+
empty_data = pd.DataFrame()
|
|
573
|
+
fake_conn = FakeConnection(frame=empty_data)
|
|
574
|
+
session = FakeSession(fake_conn)
|
|
575
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
576
|
+
|
|
577
|
+
result = overview.run()
|
|
578
|
+
|
|
579
|
+
assert isinstance(result, pd.DataFrame)
|
|
580
|
+
assert result.empty
|
|
581
|
+
assert len(result.columns) > 0
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
def test_companyoverview_large_dataset_handling():
|
|
585
|
+
"""Test handling of large datasets"""
|
|
586
|
+
# Create large dataset
|
|
587
|
+
large_data = pd.DataFrame(
|
|
588
|
+
{
|
|
589
|
+
"ts_code": ["000001.SZ"] * 1000,
|
|
590
|
+
"ann_date": ["20200430"] * 1000,
|
|
591
|
+
"end_date": ["20200331"] * 1000,
|
|
592
|
+
"revenue": ["100000000.00"] * 1000,
|
|
593
|
+
"is_audit": ["1"] * 1000,
|
|
594
|
+
}
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
fake_conn = FakeConnection(frame=large_data)
|
|
598
|
+
session = FakeSession(fake_conn)
|
|
599
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
600
|
+
|
|
601
|
+
result = overview.run()
|
|
602
|
+
|
|
603
|
+
# Should deduplicate to 1 row
|
|
604
|
+
assert len(result) == 1
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
def test_companyoverview_without_cache(sample_source_data):
|
|
608
|
+
"""Test that class works correctly without caching"""
|
|
609
|
+
fake_conn = FakeConnection(frame=sample_source_data)
|
|
610
|
+
session = FakeSession(fake_conn)
|
|
611
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"}, cache=False)
|
|
612
|
+
|
|
613
|
+
result = overview.run()
|
|
614
|
+
|
|
615
|
+
assert isinstance(result, pd.DataFrame)
|
|
616
|
+
assert len(result) > 0
|
|
617
|
+
assert overview.cache is None
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
def test_companyoverview_handles_missing_numeric_fields():
|
|
621
|
+
"""Test that missing numeric fields don't break transformation"""
|
|
622
|
+
# Data with only subset of fields
|
|
623
|
+
minimal_data = pd.DataFrame(
|
|
624
|
+
{
|
|
625
|
+
"ts_code": ["000001.SZ"],
|
|
626
|
+
"ann_date": ["20200430"],
|
|
627
|
+
"end_date": ["20200331"],
|
|
628
|
+
"revenue": ["100000000.00"],
|
|
629
|
+
"is_audit": ["1"],
|
|
630
|
+
}
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
fake_conn = FakeConnection(frame=minimal_data)
|
|
634
|
+
session = FakeSession(fake_conn)
|
|
635
|
+
overview = CompanyOverview(session=session, params={"ts_code": "000001.SZ"})
|
|
636
|
+
|
|
637
|
+
result = overview.run()
|
|
638
|
+
|
|
639
|
+
# Should complete without error
|
|
640
|
+
assert len(result) == 1
|
|
641
|
+
# Missing fields should be NaN
|
|
642
|
+
assert pd.isna(result.iloc[0]["operate_profit"])
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
def test_companyoverview_api_doc_reference():
|
|
646
|
+
"""Test that class correctly references API documentation"""
|
|
647
|
+
assert "doc_id=46" in CompanyOverview.__doc__
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from xfintech.data.source.tushare.stock.companyprofit.companyprofit import (
|
|
4
|
+
CompanyProfit,
|
|
5
|
+
)
|
|
6
|
+
from xfintech.data.source.tushare.stock.companyprofit.constant import (
|
|
7
|
+
KEY,
|
|
8
|
+
NAME,
|
|
9
|
+
PAGINATE,
|
|
10
|
+
SOURCE,
|
|
11
|
+
TARGET,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"CompanyProfit",
|
|
16
|
+
"KEY",
|
|
17
|
+
"NAME",
|
|
18
|
+
"PAGINATE",
|
|
19
|
+
"SOURCE",
|
|
20
|
+
"TARGET",
|
|
21
|
+
]
|