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,207 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from xfintech.fabric.column.info import ColumnInfo, ColumnKind
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_columninfo_basic_init():
|
|
7
|
+
col = ColumnInfo(
|
|
8
|
+
name="price",
|
|
9
|
+
kind="Float",
|
|
10
|
+
desc=" 股票价格 ",
|
|
11
|
+
meta={"unit": "CNY"},
|
|
12
|
+
)
|
|
13
|
+
assert col.name == "price"
|
|
14
|
+
assert col.kind == ColumnKind.FLOAT
|
|
15
|
+
assert col.desc == "股票价格"
|
|
16
|
+
assert col.meta == {"unit": "CNY"}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_columninfo_name_must_be_valid():
|
|
20
|
+
with pytest.raises(ValueError):
|
|
21
|
+
ColumnInfo(name="1invalid")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_columninfo_name_is_lowercase():
|
|
25
|
+
col = ColumnInfo(name="PriceHigh")
|
|
26
|
+
assert col.name == "pricehigh"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_columninfo_kind_from_datakind_instance():
|
|
30
|
+
col = ColumnInfo(name="qty", kind=ColumnKind.INTEGER)
|
|
31
|
+
assert col.kind == ColumnKind.INTEGER
|
|
32
|
+
assert col.name == "qty"
|
|
33
|
+
assert col.meta is None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_columninfo_kind_from_str_case_insensitive():
|
|
37
|
+
col = ColumnInfo(name="qty", kind="integer")
|
|
38
|
+
assert col.kind == ColumnKind.INTEGER
|
|
39
|
+
assert col.name == "qty"
|
|
40
|
+
|
|
41
|
+
col2 = ColumnInfo(name="qty", kind="InTeGeR")
|
|
42
|
+
assert col2.kind == ColumnKind.INTEGER
|
|
43
|
+
assert col2.name == "qty"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_columninfo_invalid_kind():
|
|
47
|
+
col = ColumnInfo(name="x", kind="NOT_A_TYPE")
|
|
48
|
+
assert col.kind == ColumnKind.STRING
|
|
49
|
+
assert col.desc == ""
|
|
50
|
+
assert col.meta is None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_columninfo_default_kind_string():
|
|
54
|
+
col = ColumnInfo(name="remark")
|
|
55
|
+
assert col.kind == ColumnKind.STRING
|
|
56
|
+
assert col.meta is None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_columninfo_desc_strip():
|
|
60
|
+
col = ColumnInfo(
|
|
61
|
+
name="remark",
|
|
62
|
+
desc=" Something Here ",
|
|
63
|
+
)
|
|
64
|
+
assert col.desc == "Something Here"
|
|
65
|
+
assert col.meta is None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_columninfo_desc_empty_when_none():
|
|
69
|
+
col = ColumnInfo(name="remark", desc=None)
|
|
70
|
+
assert col.desc == ""
|
|
71
|
+
assert col.meta is None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_columninfo_meta_bytes_to_str():
|
|
75
|
+
col = ColumnInfo(
|
|
76
|
+
name="flag",
|
|
77
|
+
meta={
|
|
78
|
+
b"bin": b"yes",
|
|
79
|
+
"code": b"ok",
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
assert col.meta == {"bin": "yes", "code": "ok"}
|
|
83
|
+
assert col.desc == ""
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_columninfo_meta_str_normal():
|
|
87
|
+
col = ColumnInfo(name="flag", meta={"x": 1})
|
|
88
|
+
assert col.meta == {"x": 1}
|
|
89
|
+
assert col.desc == ""
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_columninfo_update_kind_desc_meta():
|
|
93
|
+
col = ColumnInfo(
|
|
94
|
+
name="price",
|
|
95
|
+
kind="float",
|
|
96
|
+
desc="old",
|
|
97
|
+
meta={"unit": "CNY"},
|
|
98
|
+
)
|
|
99
|
+
col.update(
|
|
100
|
+
kind="integer",
|
|
101
|
+
desc="new-desc",
|
|
102
|
+
meta={"precision": 2},
|
|
103
|
+
)
|
|
104
|
+
assert col.kind == ColumnKind.INTEGER
|
|
105
|
+
assert col.desc == "new-desc"
|
|
106
|
+
assert col.meta == {"unit": "CNY", "precision": 2}
|
|
107
|
+
assert col.name == "price"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_columninfo_add_methods():
|
|
111
|
+
col = ColumnInfo(name="level")
|
|
112
|
+
col.add_desc("some desc")
|
|
113
|
+
assert col.desc == "some desc"
|
|
114
|
+
|
|
115
|
+
col.add_meta("k", "v")
|
|
116
|
+
assert col.meta["k"] == "v"
|
|
117
|
+
|
|
118
|
+
col.add_kind("Boolean")
|
|
119
|
+
assert col.kind == ColumnKind.BOOLEAN
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_full_columninfo_to_dict_and_describe():
|
|
123
|
+
col = ColumnInfo(
|
|
124
|
+
name="amount",
|
|
125
|
+
kind="Float",
|
|
126
|
+
desc="amt",
|
|
127
|
+
meta={"unit": "usd"},
|
|
128
|
+
)
|
|
129
|
+
d1 = col.to_dict()
|
|
130
|
+
assert d1["name"] == "amount"
|
|
131
|
+
assert d1["kind"] == "Float"
|
|
132
|
+
assert d1["desc"] == "amt"
|
|
133
|
+
assert d1["meta"] == {"unit": "usd"}
|
|
134
|
+
|
|
135
|
+
d2 = col.describe()
|
|
136
|
+
assert d2["name"] == "amount"
|
|
137
|
+
assert d2["kind"] == "Float"
|
|
138
|
+
assert d2["desc"] == "amt"
|
|
139
|
+
assert d2["meta"] == {"unit": "usd"}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_partial_columninfo_to_dict_and_describe():
|
|
143
|
+
col2 = ColumnInfo(
|
|
144
|
+
name="flag",
|
|
145
|
+
kind="Boolean",
|
|
146
|
+
)
|
|
147
|
+
d3 = col2.to_dict()
|
|
148
|
+
assert d3["name"] == "flag"
|
|
149
|
+
assert d3["kind"] == "Boolean"
|
|
150
|
+
assert d3["desc"] == ""
|
|
151
|
+
assert d3["meta"] is None
|
|
152
|
+
|
|
153
|
+
d4 = col2.describe()
|
|
154
|
+
assert d4["name"] == "flag"
|
|
155
|
+
assert d4["kind"] == "Boolean"
|
|
156
|
+
assert "desc" not in d4
|
|
157
|
+
assert "meta" not in d4
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def test_columninfo_str_and_repr():
|
|
161
|
+
col = ColumnInfo(name="price", kind="Float")
|
|
162
|
+
s = str(col)
|
|
163
|
+
assert "price: Float" in s
|
|
164
|
+
|
|
165
|
+
r = repr(col)
|
|
166
|
+
assert "name" in r
|
|
167
|
+
assert "price" in r
|
|
168
|
+
assert "Float" in r
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def test_columninfo_identifier_is_deterministic():
|
|
172
|
+
col1 = ColumnInfo(
|
|
173
|
+
name="amount",
|
|
174
|
+
kind="Float",
|
|
175
|
+
desc="amt",
|
|
176
|
+
meta={"unit": "usd"},
|
|
177
|
+
)
|
|
178
|
+
col2 = ColumnInfo(
|
|
179
|
+
name="amount",
|
|
180
|
+
kind="Float",
|
|
181
|
+
desc="amt",
|
|
182
|
+
meta={"unit": "usd"},
|
|
183
|
+
)
|
|
184
|
+
assert col1.identifier == col2.identifier
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def test_columninfo_identifier_not_change_with_meta():
|
|
188
|
+
col1 = ColumnInfo(
|
|
189
|
+
name="amount",
|
|
190
|
+
kind="Float",
|
|
191
|
+
desc="amt",
|
|
192
|
+
meta={"unit": "usd"},
|
|
193
|
+
)
|
|
194
|
+
col2 = ColumnInfo(
|
|
195
|
+
name="amount",
|
|
196
|
+
kind="Float",
|
|
197
|
+
desc="amt",
|
|
198
|
+
meta={"unit": "eur"},
|
|
199
|
+
)
|
|
200
|
+
col3 = ColumnInfo(
|
|
201
|
+
name="volume",
|
|
202
|
+
kind="Float",
|
|
203
|
+
desc="amt",
|
|
204
|
+
meta={"unit": "eur"},
|
|
205
|
+
)
|
|
206
|
+
assert col1.identifier == col2.identifier
|
|
207
|
+
assert col1.identifier != col3.identifier
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from xfintech.fabric.column.kind import ColumnKind
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_datakind_members_exist():
|
|
7
|
+
assert ColumnKind.INTEGER.value == "Integer"
|
|
8
|
+
assert ColumnKind.FLOAT.value == "Float"
|
|
9
|
+
assert ColumnKind.STRING.value == "String"
|
|
10
|
+
assert ColumnKind.BOOLEAN.value == "Boolean"
|
|
11
|
+
assert ColumnKind.DATETIME.value == "Datetime"
|
|
12
|
+
assert ColumnKind.CATEGORICAL.value == "Categorical"
|
|
13
|
+
assert ColumnKind.DATE.value == "Date"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_from_str_basic_cases():
|
|
17
|
+
assert ColumnKind.from_str("Integer") == ColumnKind.INTEGER
|
|
18
|
+
assert ColumnKind.from_str("Float") == ColumnKind.FLOAT
|
|
19
|
+
assert ColumnKind.from_str("String") == ColumnKind.STRING
|
|
20
|
+
assert ColumnKind.from_str("Boolean") == ColumnKind.BOOLEAN
|
|
21
|
+
assert ColumnKind.from_str("Datetime") == ColumnKind.DATETIME
|
|
22
|
+
assert ColumnKind.from_str("Categorical") == ColumnKind.CATEGORICAL
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_from_str_case_insensitive():
|
|
26
|
+
assert ColumnKind.from_str("integer") == ColumnKind.INTEGER
|
|
27
|
+
assert ColumnKind.from_str("FLOAT") == ColumnKind.FLOAT
|
|
28
|
+
assert ColumnKind.from_str("sTrInG") == ColumnKind.STRING
|
|
29
|
+
assert ColumnKind.from_str("boolean") == ColumnKind.BOOLEAN
|
|
30
|
+
assert ColumnKind.from_str("DATETIME") == ColumnKind.DATETIME
|
|
31
|
+
assert ColumnKind.from_str("cAtEgOrIcAl") == ColumnKind.CATEGORICAL
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_from_str_unknown_returns_unknown():
|
|
35
|
+
assert ColumnKind.from_str("SomethingElse") == ColumnKind.STRING
|
|
36
|
+
assert ColumnKind.from_str("") == ColumnKind.STRING
|
|
37
|
+
assert ColumnKind.from_str("???") == ColumnKind.STRING
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_str_representation():
|
|
41
|
+
assert str(ColumnKind.INTEGER) == "Integer"
|
|
42
|
+
assert str(ColumnKind.STRING) == "String"
|
|
43
|
+
assert str(ColumnKind.DATE) == "Date"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_repr_representation():
|
|
47
|
+
assert repr(ColumnKind.INTEGER) == "ColumnKind.INTEGER"
|
|
48
|
+
assert repr(ColumnKind.CATEGORICAL) == "ColumnKind.CATEGORICAL"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_equality_with_string():
|
|
52
|
+
assert ColumnKind.INTEGER == "Integer"
|
|
53
|
+
assert ColumnKind.FLOAT == "float"
|
|
54
|
+
assert ColumnKind.STRING != "Boolean"
|
|
55
|
+
assert ColumnKind.DATETIME != "datetime2"
|
|
56
|
+
assert ColumnKind.CATEGORICAL == "CATEGORICAL"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_inequality_with_string():
|
|
60
|
+
assert ColumnKind.INTEGER != "Float"
|
|
61
|
+
assert ColumnKind.BOOLEAN != "boolean2"
|
|
62
|
+
assert ColumnKind.DATE != "DateTime"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_equality_with_enum():
|
|
66
|
+
assert ColumnKind.INTEGER == ColumnKind.INTEGER
|
|
67
|
+
assert ColumnKind.FLOAT != ColumnKind.STRING
|
|
68
|
+
assert ColumnKind.DATE == ColumnKind.DATE
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_inequality_with_enum():
|
|
72
|
+
assert ColumnKind.INTEGER != ColumnKind.FLOAT
|
|
73
|
+
assert ColumnKind.BOOLEAN != ColumnKind.DATETIME
|
|
74
|
+
assert ColumnKind.CATEGORICAL != ColumnKind.DATE
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_missing_method():
|
|
78
|
+
assert ColumnKind("integer") == ColumnKind.INTEGER
|
|
79
|
+
assert ColumnKind("FLOAT") == ColumnKind.FLOAT
|
|
80
|
+
assert ColumnKind("unknown_value") == ColumnKind.STRING
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
import re
|
|
6
|
+
from typing import Any, Dict, List, Optional
|
|
7
|
+
|
|
8
|
+
from xfintech.fabric.column.info import ColumnInfo
|
|
9
|
+
from xfintech.fabric.column.kind import ColumnKind
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TableInfo:
|
|
13
|
+
"""
|
|
14
|
+
描述:
|
|
15
|
+
- 表信息。
|
|
16
|
+
|
|
17
|
+
参数:
|
|
18
|
+
- name: str, optional, 表名称。 默认为空字符串。
|
|
19
|
+
- desc: str, optional, 表描述信息。 默认为空字符串。
|
|
20
|
+
- meta: Dict[str, Any], optional, 表元数据。 默认为None。
|
|
21
|
+
- columns: List[ColumnInfo], optional, 列字段信息列表。 默认为空。
|
|
22
|
+
|
|
23
|
+
属性:
|
|
24
|
+
- name: str, 表名称,统一为小写。
|
|
25
|
+
- desc: str, 表描述信息。
|
|
26
|
+
- meta: Dict[str, Any], 表元数据。
|
|
27
|
+
- columns: Dict[str, ColumnInfo], 列字段信息字典,键为列名称(小写)。
|
|
28
|
+
|
|
29
|
+
方法:
|
|
30
|
+
- from_dict(data): 从字典创建 TableInfo 实例。
|
|
31
|
+
- get_column(name): 根据列名称获取 ColumnInfo 实例。
|
|
32
|
+
- remove_column(name): 根据列名称移除 ColumnInfo 实例。
|
|
33
|
+
- add_column(column): 添加 ColumnInfo 实例。
|
|
34
|
+
- update_column(name, new, kind, desc, meta): 更新列字段信息。
|
|
35
|
+
- rename_column(old, new): 重命名列字段。
|
|
36
|
+
- list_columns(): 列出所有 ColumnInfo 实例。
|
|
37
|
+
- describe(): 返回表信息的描述字典。
|
|
38
|
+
- to_dict(): 返回表信息的字典表示。
|
|
39
|
+
|
|
40
|
+
例子:
|
|
41
|
+
```python
|
|
42
|
+
from xfintech.fabric.table.info import TableInfo
|
|
43
|
+
from xfintech.fabric.column.info import ColumnInfo
|
|
44
|
+
from xfintech.fabric.column.kind import ColumnKind
|
|
45
|
+
|
|
46
|
+
table = TableInfo(
|
|
47
|
+
desc="日线行情表",
|
|
48
|
+
meta={"source": "tushare"},
|
|
49
|
+
columns=[
|
|
50
|
+
ColumnInfo(
|
|
51
|
+
name="price",
|
|
52
|
+
kind="Float",
|
|
53
|
+
desc="收盘价",
|
|
54
|
+
),
|
|
55
|
+
ColumnInfo(
|
|
56
|
+
name="volume",
|
|
57
|
+
kind=ColumnKind.INTEGER,
|
|
58
|
+
desc="成交量",
|
|
59
|
+
meta={"unit": "shares"},
|
|
60
|
+
),
|
|
61
|
+
],
|
|
62
|
+
)
|
|
63
|
+
print(table.describe())
|
|
64
|
+
```
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
_NAME_PATTERN = re.compile(r"^[A-Za-z_][A-Za-z0-9_-]*$")
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def from_dict(
|
|
71
|
+
cls,
|
|
72
|
+
data: Dict[str, Any],
|
|
73
|
+
) -> "TableInfo":
|
|
74
|
+
return cls(
|
|
75
|
+
name=data.get("name"),
|
|
76
|
+
desc=data.get("desc"),
|
|
77
|
+
meta=data.get("meta"),
|
|
78
|
+
columns=data.get("columns"),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def __init__(
|
|
82
|
+
self,
|
|
83
|
+
name: Optional[str] = None,
|
|
84
|
+
desc: Optional[str] = None,
|
|
85
|
+
meta: Optional[Dict[str, Any]] = None,
|
|
86
|
+
columns: Optional[List[ColumnInfo | Dict[str, Any]]] = None,
|
|
87
|
+
):
|
|
88
|
+
self.name = self._resolve_name(name)
|
|
89
|
+
self.desc = self._resolve_desc(desc)
|
|
90
|
+
self.meta = self._resolve_meta(meta)
|
|
91
|
+
self.columns = self._resolve_columns(columns)
|
|
92
|
+
|
|
93
|
+
def _resolve_name(
|
|
94
|
+
self,
|
|
95
|
+
value: Optional[str],
|
|
96
|
+
) -> str:
|
|
97
|
+
if not value:
|
|
98
|
+
return ""
|
|
99
|
+
else:
|
|
100
|
+
value = value.strip()
|
|
101
|
+
if not self._NAME_PATTERN.match(value):
|
|
102
|
+
raise ValueError(f"Invalid table name: {value}")
|
|
103
|
+
else:
|
|
104
|
+
return value.lower()
|
|
105
|
+
|
|
106
|
+
def _resolve_desc(
|
|
107
|
+
self,
|
|
108
|
+
value: Optional[str],
|
|
109
|
+
) -> Optional[str]:
|
|
110
|
+
if value is None:
|
|
111
|
+
return ""
|
|
112
|
+
else:
|
|
113
|
+
return value.strip()
|
|
114
|
+
|
|
115
|
+
def _resolve_meta(
|
|
116
|
+
self,
|
|
117
|
+
meta: Optional[Dict[str, Any]],
|
|
118
|
+
) -> Optional[Dict[str, Any]]:
|
|
119
|
+
if meta is None:
|
|
120
|
+
return None
|
|
121
|
+
resolved: Dict[str, Any] = {}
|
|
122
|
+
for k, v in meta.items():
|
|
123
|
+
if isinstance(v, bytes):
|
|
124
|
+
v = v.decode("utf8")
|
|
125
|
+
if isinstance(k, bytes):
|
|
126
|
+
k = k.decode("utf8")
|
|
127
|
+
resolved[k] = v
|
|
128
|
+
return resolved
|
|
129
|
+
|
|
130
|
+
def _resolve_columns(
|
|
131
|
+
self,
|
|
132
|
+
columns: Optional[List[ColumnInfo | Dict[str, Any]]],
|
|
133
|
+
) -> Dict[str, ColumnInfo]:
|
|
134
|
+
if columns is None:
|
|
135
|
+
return {}
|
|
136
|
+
|
|
137
|
+
resolved: Dict[str, ColumnInfo] = {}
|
|
138
|
+
for item in columns:
|
|
139
|
+
if isinstance(item, ColumnInfo):
|
|
140
|
+
resolved[item.name] = item
|
|
141
|
+
elif isinstance(item, dict):
|
|
142
|
+
col = ColumnInfo.from_dict(item)
|
|
143
|
+
resolved[col.name] = col
|
|
144
|
+
else:
|
|
145
|
+
raise TypeError(f"Invalid column type: {type(item)}")
|
|
146
|
+
return resolved
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def identifier(self) -> str:
|
|
150
|
+
result = {}
|
|
151
|
+
result["name"] = self.name
|
|
152
|
+
result["desc"] = self.desc
|
|
153
|
+
result["columns"] = []
|
|
154
|
+
values = sorted(
|
|
155
|
+
self.columns.values(),
|
|
156
|
+
key=lambda c: c.name,
|
|
157
|
+
)
|
|
158
|
+
for col in values:
|
|
159
|
+
result["columns"].append(
|
|
160
|
+
{
|
|
161
|
+
"name": col.name,
|
|
162
|
+
"kind": col.kind.value,
|
|
163
|
+
}
|
|
164
|
+
)
|
|
165
|
+
dna = json.dumps(
|
|
166
|
+
result,
|
|
167
|
+
sort_keys=True,
|
|
168
|
+
ensure_ascii=False,
|
|
169
|
+
separators=(",", ":"),
|
|
170
|
+
)
|
|
171
|
+
return hashlib.sha256(dna.encode("utf-8")).hexdigest()
|
|
172
|
+
|
|
173
|
+
def __str__(self) -> str:
|
|
174
|
+
return self.columns.__str__()
|
|
175
|
+
|
|
176
|
+
def __repr__(self) -> str:
|
|
177
|
+
return f"{self.__class__.__name__}(name={self.name})"
|
|
178
|
+
|
|
179
|
+
def get_column(
|
|
180
|
+
self,
|
|
181
|
+
name: str,
|
|
182
|
+
) -> Optional[ColumnInfo]:
|
|
183
|
+
return self.columns.get(name.lower())
|
|
184
|
+
|
|
185
|
+
def remove_column(
|
|
186
|
+
self,
|
|
187
|
+
name: str,
|
|
188
|
+
) -> "TableInfo":
|
|
189
|
+
key = name.lower()
|
|
190
|
+
if key in self.columns:
|
|
191
|
+
del self.columns[key]
|
|
192
|
+
return self
|
|
193
|
+
|
|
194
|
+
def add_column(
|
|
195
|
+
self,
|
|
196
|
+
column: ColumnInfo | Dict[str, Any],
|
|
197
|
+
) -> "TableInfo":
|
|
198
|
+
if isinstance(column, dict):
|
|
199
|
+
column = ColumnInfo.from_dict(column)
|
|
200
|
+
self.columns[column.name] = column
|
|
201
|
+
return self
|
|
202
|
+
|
|
203
|
+
def update_column(
|
|
204
|
+
self,
|
|
205
|
+
name: str,
|
|
206
|
+
new: Optional[str] = None,
|
|
207
|
+
kind: Optional[ColumnKind | str] = None,
|
|
208
|
+
desc: Optional[str] = None,
|
|
209
|
+
meta: Optional[Dict[str, Any]] = None,
|
|
210
|
+
) -> "TableInfo":
|
|
211
|
+
oldkey = name.lower()
|
|
212
|
+
if oldkey in self.columns:
|
|
213
|
+
self.columns[oldkey].update(
|
|
214
|
+
kind=kind,
|
|
215
|
+
desc=desc,
|
|
216
|
+
meta=meta,
|
|
217
|
+
)
|
|
218
|
+
if new is not None:
|
|
219
|
+
self.rename_column(
|
|
220
|
+
old=name,
|
|
221
|
+
new=new,
|
|
222
|
+
)
|
|
223
|
+
return self
|
|
224
|
+
|
|
225
|
+
def rename_column(
|
|
226
|
+
self,
|
|
227
|
+
old: str,
|
|
228
|
+
new: str,
|
|
229
|
+
) -> "TableInfo":
|
|
230
|
+
oldkey = old.lower()
|
|
231
|
+
newkey = new.lower()
|
|
232
|
+
if oldkey in self.columns:
|
|
233
|
+
self.columns[oldkey].update(name=new)
|
|
234
|
+
self.columns[newkey] = self.columns[oldkey]
|
|
235
|
+
del self.columns[oldkey]
|
|
236
|
+
return self
|
|
237
|
+
|
|
238
|
+
def list_columns(self) -> List[ColumnInfo]:
|
|
239
|
+
return list(self.columns.values())
|
|
240
|
+
|
|
241
|
+
def list_column_names(self) -> List[str]:
|
|
242
|
+
return list(self.columns.keys())
|
|
243
|
+
|
|
244
|
+
def describe(self) -> Dict[str, Any]:
|
|
245
|
+
result = {}
|
|
246
|
+
if self.name:
|
|
247
|
+
result["name"] = self.name
|
|
248
|
+
if self.desc:
|
|
249
|
+
result["desc"] = self.desc
|
|
250
|
+
if self.meta:
|
|
251
|
+
result["meta"] = self.meta
|
|
252
|
+
if self.columns:
|
|
253
|
+
result["columns"] = [c.describe() for c in self.list_columns()]
|
|
254
|
+
return result
|
|
255
|
+
|
|
256
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
257
|
+
return {
|
|
258
|
+
"identifier": self.identifier,
|
|
259
|
+
"name": self.name,
|
|
260
|
+
"desc": self.desc,
|
|
261
|
+
"meta": self.meta,
|
|
262
|
+
"columns": [c.to_dict() for c in self.list_columns()],
|
|
263
|
+
}
|
|
File without changes
|