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,17 @@
|
|
|
1
|
+
from xfintech.data.job.errors import (
|
|
2
|
+
JobAlreadyRegisteredError,
|
|
3
|
+
JobNameError,
|
|
4
|
+
JobNotFoundError,
|
|
5
|
+
)
|
|
6
|
+
from xfintech.data.job.house import House
|
|
7
|
+
from xfintech.data.job.joblike import JobLike
|
|
8
|
+
|
|
9
|
+
JobHouse = House() # 创建一个全局的 JobHouse 实例
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"JobNotFoundError",
|
|
13
|
+
"JobAlreadyRegisteredError",
|
|
14
|
+
"JobNameError",
|
|
15
|
+
"JobHouse",
|
|
16
|
+
"JobLike",
|
|
17
|
+
]
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class JobNotFoundError(KeyError):
|
|
5
|
+
"""
|
|
6
|
+
描述:
|
|
7
|
+
- Job 未找到异常,当尝试查找不存在的 Job 名称或别名时抛出。
|
|
8
|
+
- 继承自 KeyError,表示键查找失败。
|
|
9
|
+
|
|
10
|
+
参数:
|
|
11
|
+
- message: str, 错误信息,通常包含未找到的 Job 名称。
|
|
12
|
+
|
|
13
|
+
方法:
|
|
14
|
+
- 继承自 KeyError 的所有方法。
|
|
15
|
+
|
|
16
|
+
例子:
|
|
17
|
+
```python
|
|
18
|
+
from xfintech.data.job.house import House
|
|
19
|
+
from xfintech.data.job.errors import JobNotFoundError
|
|
20
|
+
|
|
21
|
+
house = House()
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
house.lookup("nonexistent_job")
|
|
25
|
+
except JobNotFoundError as e:
|
|
26
|
+
print(f"Error: {e}") # Error: job not found: nonexistent_job
|
|
27
|
+
```
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class JobAlreadyRegisteredError(KeyError):
|
|
34
|
+
"""
|
|
35
|
+
描述:
|
|
36
|
+
- Job 已注册异常,当尝试注册已存在的 Job 名称或别名时抛出(replace=False)。
|
|
37
|
+
- 继承自 KeyError,表示键冲突。
|
|
38
|
+
|
|
39
|
+
参数:
|
|
40
|
+
- message: str, 错误信息,通常包含冲突的 Job 名称或别名。
|
|
41
|
+
|
|
42
|
+
方法:
|
|
43
|
+
- 继承自 KeyError 的所有方法。
|
|
44
|
+
|
|
45
|
+
例子:
|
|
46
|
+
```python
|
|
47
|
+
from xfintech.data.job.house import House
|
|
48
|
+
from xfintech.data.job.errors import JobAlreadyRegisteredError
|
|
49
|
+
|
|
50
|
+
house = House()
|
|
51
|
+
|
|
52
|
+
@house.register("my_job")
|
|
53
|
+
class MyJob:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
# 尝试重复注册会抛出异常
|
|
57
|
+
try:
|
|
58
|
+
@house.register("my_job")
|
|
59
|
+
class AnotherJob:
|
|
60
|
+
pass
|
|
61
|
+
except JobAlreadyRegisteredError as e:
|
|
62
|
+
print(f"Error: {e}") # Error: Job already registered: my_job
|
|
63
|
+
|
|
64
|
+
# 使用 replace=True 可以覆盖
|
|
65
|
+
@house.register("my_job", replace=True)
|
|
66
|
+
class ReplacedJob:
|
|
67
|
+
pass
|
|
68
|
+
```
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class JobNameError(ValueError):
|
|
75
|
+
"""
|
|
76
|
+
描述:
|
|
77
|
+
- Job 名称错误异常,当提供的 Job 名称格式不正确时抛出。
|
|
78
|
+
- 继承自 ValueError,表示值不合法。
|
|
79
|
+
- 名称必须是非空字符串。
|
|
80
|
+
|
|
81
|
+
参数:
|
|
82
|
+
- message: str, 错误信息,描述名称错误的原因。
|
|
83
|
+
|
|
84
|
+
方法:
|
|
85
|
+
- 继承自 ValueError 的所有方法。
|
|
86
|
+
|
|
87
|
+
例子:
|
|
88
|
+
```python
|
|
89
|
+
from xfintech.data.job.house import House
|
|
90
|
+
from xfintech.data.job.errors import JobNameError
|
|
91
|
+
|
|
92
|
+
house = House()
|
|
93
|
+
|
|
94
|
+
# 空字符串名称会抛出异常
|
|
95
|
+
try:
|
|
96
|
+
@house.register("")
|
|
97
|
+
class MyJob:
|
|
98
|
+
pass
|
|
99
|
+
except JobNameError as e:
|
|
100
|
+
print(f"Error: {e}") # Error: job name cannot be empty
|
|
101
|
+
|
|
102
|
+
# 非字符串类型会抛出异常
|
|
103
|
+
try:
|
|
104
|
+
@house.register(123)
|
|
105
|
+
class MyJob:
|
|
106
|
+
pass
|
|
107
|
+
except JobNameError as e:
|
|
108
|
+
print(f"Error: {e}") # Error: job name must be str, got <class 'int'>
|
|
109
|
+
```
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
pass
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from xfintech.data.job.errors import (
|
|
6
|
+
JobAlreadyRegisteredError,
|
|
7
|
+
JobNameError,
|
|
8
|
+
JobNotFoundError,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class House:
|
|
13
|
+
"""
|
|
14
|
+
描述:
|
|
15
|
+
- Job 注册和管理容器,提供 Job 类的注册、查找和创建功能。
|
|
16
|
+
- 支持 Job 别名机制,允许一个 Job 类有多个访问名称。
|
|
17
|
+
- 所有名称不区分大小写,自动归一化处理。
|
|
18
|
+
- 提供装饰器模式注册 Job 类。
|
|
19
|
+
|
|
20
|
+
参数:
|
|
21
|
+
- 无参数。
|
|
22
|
+
|
|
23
|
+
属性:
|
|
24
|
+
- _jobs: dict[str, type], Job 名称到类的映射字典。
|
|
25
|
+
- _aliases: dict[str, str], 别名到 Job 名称的映射字典。
|
|
26
|
+
|
|
27
|
+
方法:
|
|
28
|
+
- register(name, alias=None, replace=False): 装饰器方法,注册 Job 类。
|
|
29
|
+
- lookup(name): 根据名称或别名查找 Job 类。
|
|
30
|
+
- create(name, *args, **kwargs): 根据名称创建 Job 实例。
|
|
31
|
+
- list(): 返回所有已注册的 Job 名称列表。
|
|
32
|
+
|
|
33
|
+
例子:
|
|
34
|
+
```python
|
|
35
|
+
from xfintech.data.job.house import House
|
|
36
|
+
|
|
37
|
+
# 创建 House 实例
|
|
38
|
+
house = House()
|
|
39
|
+
|
|
40
|
+
# 使用装饰器注册 Job
|
|
41
|
+
@house.register("stock_daily", alias="daily")
|
|
42
|
+
class StockDailyJob:
|
|
43
|
+
def __init__(self, symbol):
|
|
44
|
+
self.symbol = symbol
|
|
45
|
+
|
|
46
|
+
def run(self):
|
|
47
|
+
return f"Running daily job for {self.symbol}"
|
|
48
|
+
|
|
49
|
+
# 查找 Job 类
|
|
50
|
+
JobClass = house.lookup("stock_daily")
|
|
51
|
+
print(JobClass) # <class 'StockDailyJob'>
|
|
52
|
+
|
|
53
|
+
# 通过别名查找
|
|
54
|
+
JobClass = house.lookup("daily")
|
|
55
|
+
print(JobClass) # <class 'StockDailyJob'>
|
|
56
|
+
|
|
57
|
+
# 创建 Job 实例
|
|
58
|
+
job = house.create("stock_daily", symbol="AAPL")
|
|
59
|
+
print(job.run()) # Running daily job for AAPL
|
|
60
|
+
|
|
61
|
+
# 通过别名创建
|
|
62
|
+
job = house.create("daily", symbol="TSLA")
|
|
63
|
+
print(job.run()) # Running daily job for TSLA
|
|
64
|
+
|
|
65
|
+
# 列出所有注册的 Job
|
|
66
|
+
jobs = house.list()
|
|
67
|
+
print(jobs) # ['stock_daily']
|
|
68
|
+
|
|
69
|
+
# 名称不区分大小写
|
|
70
|
+
JobClass = house.lookup("STOCK_DAILY")
|
|
71
|
+
JobClass = house.lookup("Stock_Daily")
|
|
72
|
+
|
|
73
|
+
# 替换已注册的 Job
|
|
74
|
+
@house.register("stock_daily", replace=True)
|
|
75
|
+
class NewStockDailyJob:
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
# 错误处理示例
|
|
79
|
+
from xfintech.data.job.errors import JobNotFoundError
|
|
80
|
+
try:
|
|
81
|
+
house.lookup("nonexistent")
|
|
82
|
+
except JobNotFoundError as e:
|
|
83
|
+
print(f"Error: {e}") # Error: job not found: nonexistent
|
|
84
|
+
```
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def __init__(self) -> None:
|
|
88
|
+
self._jobs: dict[str, type] = {}
|
|
89
|
+
self._aliases: dict[str, str] = {}
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def _normalize_name(
|
|
93
|
+
name: str,
|
|
94
|
+
) -> str:
|
|
95
|
+
if not isinstance(name, str):
|
|
96
|
+
raise JobNameError(f"job name must be str, got {type(name)}")
|
|
97
|
+
key = name.strip().lower()
|
|
98
|
+
if not key:
|
|
99
|
+
raise JobNameError("job name cannot be empty")
|
|
100
|
+
return key
|
|
101
|
+
|
|
102
|
+
def register(
|
|
103
|
+
self,
|
|
104
|
+
name: str,
|
|
105
|
+
alias: str | None = None,
|
|
106
|
+
replace: bool = False,
|
|
107
|
+
strict: bool = False,
|
|
108
|
+
):
|
|
109
|
+
namekey = self._normalize_name(name)
|
|
110
|
+
|
|
111
|
+
def deco(cls):
|
|
112
|
+
name_in_use = namekey in self._jobs
|
|
113
|
+
if (not replace) and (name_in_use):
|
|
114
|
+
if strict:
|
|
115
|
+
msg = f"Job already registered: {namekey}"
|
|
116
|
+
raise JobAlreadyRegisteredError(msg)
|
|
117
|
+
else:
|
|
118
|
+
self._jobs[namekey] = cls
|
|
119
|
+
|
|
120
|
+
if alias is not None:
|
|
121
|
+
aliaskey = self._normalize_name(alias)
|
|
122
|
+
aliaskey_in_use = aliaskey in self._aliases
|
|
123
|
+
if (not replace) and (aliaskey_in_use) and (self._aliases[aliaskey] != namekey):
|
|
124
|
+
msg = f"Alias already used: {aliaskey}"
|
|
125
|
+
raise JobAlreadyRegisteredError(msg)
|
|
126
|
+
self._aliases[aliaskey] = namekey
|
|
127
|
+
|
|
128
|
+
cls.__job_name__ = namekey
|
|
129
|
+
return cls
|
|
130
|
+
|
|
131
|
+
return deco
|
|
132
|
+
|
|
133
|
+
def lookup(
|
|
134
|
+
self,
|
|
135
|
+
name: str,
|
|
136
|
+
) -> type:
|
|
137
|
+
key = self._normalize_name(name)
|
|
138
|
+
if key in self._jobs:
|
|
139
|
+
return self._jobs[key]
|
|
140
|
+
if key in self._aliases:
|
|
141
|
+
return self._jobs[self._aliases[key]]
|
|
142
|
+
raise JobNotFoundError(f"job not found: {name}")
|
|
143
|
+
|
|
144
|
+
def create(
|
|
145
|
+
self,
|
|
146
|
+
name: str,
|
|
147
|
+
*args,
|
|
148
|
+
**kwargs,
|
|
149
|
+
) -> Any:
|
|
150
|
+
return self.lookup(name)(*args, **kwargs)
|
|
151
|
+
|
|
152
|
+
def list(self) -> list[str]:
|
|
153
|
+
keys = self._jobs.keys()
|
|
154
|
+
aliases = self._aliases.keys()
|
|
155
|
+
items = list(keys) + list(aliases)
|
|
156
|
+
return sorted(set(items))
|
xfintech/data/job/job.py
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
from xfintech.data.common.cache import Cache
|
|
6
|
+
from xfintech.data.common.coolant import Coolant
|
|
7
|
+
from xfintech.data.common.metric import Metric
|
|
8
|
+
from xfintech.data.common.paginate import Paginate
|
|
9
|
+
from xfintech.data.common.params import Params
|
|
10
|
+
from xfintech.data.common.retry import Retry
|
|
11
|
+
from xfintech.data.job.joblike import JobLike
|
|
12
|
+
from xfintech.fabric.table.info import TableInfo
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Job(JobLike):
|
|
16
|
+
"""
|
|
17
|
+
描述:
|
|
18
|
+
- 作业基类,用于管理数据请求任务的执行、重试、缓存和监控。
|
|
19
|
+
- 集成参数管理、分页、冷却、重试、缓存和性能度量等功能。
|
|
20
|
+
- 提供完整的作业生命周期管理,包括初始化、执行、重置等。
|
|
21
|
+
- 子类需实现 _run() 方法来定义具体的执行逻辑。
|
|
22
|
+
|
|
23
|
+
属性:
|
|
24
|
+
- name: str, 作业名称。
|
|
25
|
+
- key: str, 作业唯一标识键。
|
|
26
|
+
- source: Optional[TableInfo], 数据源表信息。
|
|
27
|
+
- target: Optional[TableInfo], 目标表信息。
|
|
28
|
+
- params: Params, 作业参数对象。
|
|
29
|
+
- coolant: Coolant, 冷却控制对象,用于速率限制。
|
|
30
|
+
- paginate: Paginate, 分页管理对象。
|
|
31
|
+
- retry: Retry, 重试策略对象。
|
|
32
|
+
- cache: Optional[Cache], 缓存管理对象。
|
|
33
|
+
- metric: Metric, 性能度量对象,记录执行时间和错误。
|
|
34
|
+
|
|
35
|
+
方法:
|
|
36
|
+
- run(): 执行作业,包含重试逻辑和性能度量。
|
|
37
|
+
- _run(): 抽象方法,子类必须实现具体的执行逻辑。
|
|
38
|
+
- markpoint(name): 在 metric 中标记检查点。
|
|
39
|
+
- cool(): 执行冷却等待。
|
|
40
|
+
- get_params(): 获取作业参数字典。
|
|
41
|
+
- get_cache(unit): 从缓存获取数据。
|
|
42
|
+
- set_cache(unit, data): 将数据保存到缓存。
|
|
43
|
+
- reset(): 重置 metric 和清空缓存。
|
|
44
|
+
- describe(): 返回作业描述信息(不包含敏感数据)。
|
|
45
|
+
- to_dict(): 返回作业完整信息字典。
|
|
46
|
+
|
|
47
|
+
例子:
|
|
48
|
+
```python
|
|
49
|
+
from xfintech.data.job.job import Job
|
|
50
|
+
from xfintech.data.common.params import Params
|
|
51
|
+
|
|
52
|
+
# 创建自定义作业
|
|
53
|
+
class MyDataJob(Job):
|
|
54
|
+
def _run(self):
|
|
55
|
+
# 实现具体的数据获取逻辑
|
|
56
|
+
data = fetch_data(self.params)
|
|
57
|
+
return data
|
|
58
|
+
|
|
59
|
+
# 使用作业
|
|
60
|
+
job = MyDataJob(
|
|
61
|
+
name="daily_data",
|
|
62
|
+
key="daily_data_001",
|
|
63
|
+
params={"symbol": "AAPL", "date": "20240115"},
|
|
64
|
+
retry={"max_retries": 3, "interval": 5},
|
|
65
|
+
cache=True # 启用缓存
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# 执行作业
|
|
69
|
+
result = job.run()
|
|
70
|
+
|
|
71
|
+
# 查看执行信息
|
|
72
|
+
print(f"执行耗时: {job.metric.duration} 秒")
|
|
73
|
+
print(job.describe())
|
|
74
|
+
```
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
def __init__(
|
|
78
|
+
self,
|
|
79
|
+
name: str,
|
|
80
|
+
key: str,
|
|
81
|
+
source: Optional[TableInfo] = None,
|
|
82
|
+
target: Optional[TableInfo] = None,
|
|
83
|
+
params: Optional[Params | Dict[str, Any]] = None,
|
|
84
|
+
coolant: Optional[Coolant | Dict[str, Any]] = None,
|
|
85
|
+
paginate: Optional[Paginate | Dict[str, Any]] = None,
|
|
86
|
+
retry: Optional[Retry | Dict[str, Any]] = None,
|
|
87
|
+
cache: Optional[Cache | Dict[str, str] | bool] = None,
|
|
88
|
+
) -> None:
|
|
89
|
+
self.name: str = name
|
|
90
|
+
self.key: str = key
|
|
91
|
+
self.source: Optional[TableInfo] = source
|
|
92
|
+
self.target: Optional[TableInfo] = target
|
|
93
|
+
self.params: Params = self._resolve_params(params)
|
|
94
|
+
self.coolant: Coolant = self._resolve_coolant(coolant)
|
|
95
|
+
self.paginate: Paginate = self._resolve_paginate(paginate)
|
|
96
|
+
self.retry: Retry = self._resolve_retry(retry)
|
|
97
|
+
self.cache: Optional[Cache] = self._resolve_cache(cache)
|
|
98
|
+
self.metric: Metric = Metric()
|
|
99
|
+
self.markpoint("init[OK]")
|
|
100
|
+
|
|
101
|
+
def _resolve_params(
|
|
102
|
+
self,
|
|
103
|
+
params: Optional[Params | Dict[str, Any]],
|
|
104
|
+
) -> Params:
|
|
105
|
+
if params is None:
|
|
106
|
+
return Params()
|
|
107
|
+
if isinstance(params, dict):
|
|
108
|
+
return Params(**params)
|
|
109
|
+
return params
|
|
110
|
+
|
|
111
|
+
def _resolve_coolant(
|
|
112
|
+
self,
|
|
113
|
+
coolant: Optional[Coolant | Dict[str, Any]],
|
|
114
|
+
) -> Coolant:
|
|
115
|
+
if coolant is None:
|
|
116
|
+
return Coolant()
|
|
117
|
+
if isinstance(coolant, dict):
|
|
118
|
+
return Coolant.from_dict(coolant)
|
|
119
|
+
return coolant
|
|
120
|
+
|
|
121
|
+
def _resolve_paginate(
|
|
122
|
+
self,
|
|
123
|
+
paginate: Optional[Paginate | Dict[str, Any]],
|
|
124
|
+
) -> Paginate:
|
|
125
|
+
if paginate is None:
|
|
126
|
+
return Paginate()
|
|
127
|
+
if isinstance(paginate, dict):
|
|
128
|
+
return Paginate.from_dict(paginate)
|
|
129
|
+
return paginate
|
|
130
|
+
|
|
131
|
+
def _resolve_retry(
|
|
132
|
+
self,
|
|
133
|
+
retry: Optional[Retry | Dict[str, Any]],
|
|
134
|
+
) -> Retry:
|
|
135
|
+
if retry is None:
|
|
136
|
+
return Retry()
|
|
137
|
+
if isinstance(retry, dict):
|
|
138
|
+
return Retry.from_dict(retry)
|
|
139
|
+
return retry
|
|
140
|
+
|
|
141
|
+
def _resolve_cache(
|
|
142
|
+
self,
|
|
143
|
+
cache: Optional[Cache | Dict[str, str] | bool],
|
|
144
|
+
) -> Optional[Cache]:
|
|
145
|
+
if isinstance(cache, bool):
|
|
146
|
+
if cache:
|
|
147
|
+
return Cache(identifier=self.name)
|
|
148
|
+
else:
|
|
149
|
+
return None
|
|
150
|
+
if isinstance(cache, dict):
|
|
151
|
+
return Cache.from_dict(cache)
|
|
152
|
+
if isinstance(cache, Cache):
|
|
153
|
+
return cache
|
|
154
|
+
return None
|
|
155
|
+
|
|
156
|
+
def run(self) -> Any:
|
|
157
|
+
wrapped = self.retry(self._run)
|
|
158
|
+
with self.metric:
|
|
159
|
+
return wrapped()
|
|
160
|
+
|
|
161
|
+
def _run(self) -> object:
|
|
162
|
+
msg = "Subclasses must implement this method."
|
|
163
|
+
raise NotImplementedError(msg)
|
|
164
|
+
|
|
165
|
+
def markpoint(
|
|
166
|
+
self,
|
|
167
|
+
name: str,
|
|
168
|
+
) -> None:
|
|
169
|
+
self.metric.mark(name)
|
|
170
|
+
|
|
171
|
+
def cool(self) -> None:
|
|
172
|
+
self.coolant.cool()
|
|
173
|
+
|
|
174
|
+
def get_params(self) -> Dict[str, Any]:
|
|
175
|
+
return self.params.to_dict()
|
|
176
|
+
|
|
177
|
+
def get_cache(
|
|
178
|
+
self,
|
|
179
|
+
unit: str,
|
|
180
|
+
default: Any = None,
|
|
181
|
+
) -> Optional[Any]:
|
|
182
|
+
if self.cache:
|
|
183
|
+
result = self.cache.get(unit)
|
|
184
|
+
if result is not None:
|
|
185
|
+
return result
|
|
186
|
+
return default
|
|
187
|
+
|
|
188
|
+
def set_cache(
|
|
189
|
+
self,
|
|
190
|
+
unit: str,
|
|
191
|
+
data: Any,
|
|
192
|
+
) -> None:
|
|
193
|
+
if self.cache:
|
|
194
|
+
self.cache.set(unit, data)
|
|
195
|
+
|
|
196
|
+
def reset(self) -> None:
|
|
197
|
+
self.metric.reset()
|
|
198
|
+
if self.cache:
|
|
199
|
+
self.cache.clear()
|
|
200
|
+
|
|
201
|
+
def definition(self) -> Dict[str, Any]:
|
|
202
|
+
result = {}
|
|
203
|
+
if self.source:
|
|
204
|
+
result["source"] = self.source.describe()
|
|
205
|
+
if self.target:
|
|
206
|
+
result["target"] = self.target.describe()
|
|
207
|
+
return result
|
|
208
|
+
|
|
209
|
+
def specification(self) -> Dict[str, Any]:
|
|
210
|
+
result = {
|
|
211
|
+
"name": self.name,
|
|
212
|
+
"key": self.key,
|
|
213
|
+
"params": self.params.describe(),
|
|
214
|
+
"coolant": self.coolant.describe(),
|
|
215
|
+
"paginate": self.paginate.describe(),
|
|
216
|
+
"retry": self.retry.describe(),
|
|
217
|
+
"metric": self.metric.describe(),
|
|
218
|
+
}
|
|
219
|
+
if self.cache:
|
|
220
|
+
result["cache"] = self.cache.describe()
|
|
221
|
+
return result
|
|
222
|
+
|
|
223
|
+
def describe(self) -> Dict[str, Any]:
|
|
224
|
+
result = self.specification()
|
|
225
|
+
if self.source:
|
|
226
|
+
result["source"] = self.source.describe()
|
|
227
|
+
if self.target:
|
|
228
|
+
result["target"] = self.target.describe()
|
|
229
|
+
return result
|
|
230
|
+
|
|
231
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
232
|
+
result = {
|
|
233
|
+
"name": self.name,
|
|
234
|
+
"key": self.key,
|
|
235
|
+
"params": self.params.to_dict(),
|
|
236
|
+
"coolant": self.coolant.to_dict(),
|
|
237
|
+
"paginate": self.paginate.to_dict(),
|
|
238
|
+
"retry": self.retry.to_dict(),
|
|
239
|
+
"metric": self.metric.to_dict(),
|
|
240
|
+
}
|
|
241
|
+
if self.source:
|
|
242
|
+
result["source"] = self.source.to_dict()
|
|
243
|
+
if self.target:
|
|
244
|
+
result["target"] = self.target.to_dict()
|
|
245
|
+
if self.cache:
|
|
246
|
+
result["cache"] = self.cache.to_dict()
|
|
247
|
+
return result
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Protocol, runtime_checkable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@runtime_checkable
|
|
7
|
+
class JobLike(Protocol):
|
|
8
|
+
"""
|
|
9
|
+
描述:
|
|
10
|
+
- 作业协议接口,定义作业类必须实现的核心方法。
|
|
11
|
+
- 使用 Protocol 实现结构化类型检查(structural typing)。
|
|
12
|
+
- 任何实现这些方法的类都会被视为符合 JobLike 协议。
|
|
13
|
+
|
|
14
|
+
方法:
|
|
15
|
+
- run(): 执行作业并返回结果。
|
|
16
|
+
- _run(): 内部执行逻辑,由子类实现。
|
|
17
|
+
- describe(): 返回作业描述信息字典。
|
|
18
|
+
- to_dict(): 返回作业完整信息字典。
|
|
19
|
+
|
|
20
|
+
例子:
|
|
21
|
+
```python
|
|
22
|
+
from xfintech.data.job.joblike import JobLike
|
|
23
|
+
|
|
24
|
+
# 任何实现这些方法的类都符合 JobLike 协议
|
|
25
|
+
class MyJob:
|
|
26
|
+
def run(self) -> Any:
|
|
27
|
+
return self._run()
|
|
28
|
+
|
|
29
|
+
def _run(self) -> Any:
|
|
30
|
+
return {"result": "success"}
|
|
31
|
+
|
|
32
|
+
def describe(self) -> Dict[str, Any]:
|
|
33
|
+
return {"name": "MyJob"}
|
|
34
|
+
|
|
35
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
36
|
+
return {"name": "MyJob", "status": "active"}
|
|
37
|
+
|
|
38
|
+
# 类型检查会通过
|
|
39
|
+
job: JobLike = MyJob()
|
|
40
|
+
result = job.run()
|
|
41
|
+
```
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def run(self) -> Any: ...
|
|
45
|
+
def _run(self) -> Any: ...
|
|
46
|
+
def describe(self) -> Dict[str, Any]: ...
|
|
47
|
+
def to_dict(self) -> Dict[str, Any]: ...
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Tests for xfintech.data.job module
|