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,71 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from xfintech.serde.common.dataformat import DataFormat
|
|
7
|
+
from xfintech.serde.common.error import (
|
|
8
|
+
SerialiserFailedError,
|
|
9
|
+
SerialiserInputTypeError,
|
|
10
|
+
SerialiserNotSupportedError,
|
|
11
|
+
)
|
|
12
|
+
from xfintech.serde.common.serialiserlike import SerialiserLike
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PythonSerialiser(SerialiserLike):
|
|
16
|
+
"""
|
|
17
|
+
描述:
|
|
18
|
+
- PythonDict序列化模块。
|
|
19
|
+
- DICT -> BYTES 的单向转换,适用于配置和轻量级数据交换。
|
|
20
|
+
|
|
21
|
+
方法:
|
|
22
|
+
- serialise(data, format, **kwargs): 通用序列化方法,仅支持 JSON 格式。
|
|
23
|
+
- to_json(data, **kwargs): 将数据编码为 JSON 字节流,编码默认 "utf-8"。
|
|
24
|
+
|
|
25
|
+
例子:
|
|
26
|
+
```python
|
|
27
|
+
from xfintech.serde.serialiser.python import PythonSerialiser
|
|
28
|
+
from xfintech.serde.common.dataformat import DataFormat
|
|
29
|
+
|
|
30
|
+
# 使用通用序列化方法(推荐)
|
|
31
|
+
bytes = PythonSerialiser.serialise(
|
|
32
|
+
data,
|
|
33
|
+
format=DataFormat.JSON,
|
|
34
|
+
)
|
|
35
|
+
```
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def serialise(
|
|
40
|
+
data: Any,
|
|
41
|
+
format: DataFormat | str,
|
|
42
|
+
**kwargs: Any,
|
|
43
|
+
) -> bytes:
|
|
44
|
+
if not isinstance(data, dict):
|
|
45
|
+
msg = f"PythonSerialiser.serialise expects dict, got {type(data)}"
|
|
46
|
+
raise SerialiserInputTypeError(msg)
|
|
47
|
+
format = DataFormat.from_any(format)
|
|
48
|
+
if format == DataFormat.JSON:
|
|
49
|
+
return PythonSerialiser.to_json(data, **kwargs)
|
|
50
|
+
else:
|
|
51
|
+
msg = f"Unsupported DataFormat for serialization: {format}"
|
|
52
|
+
raise SerialiserNotSupportedError(msg)
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def to_json(
|
|
56
|
+
data: Any,
|
|
57
|
+
**kwargs: Any,
|
|
58
|
+
) -> bytes:
|
|
59
|
+
encoding = kwargs.pop("encoding", "utf-8")
|
|
60
|
+
kwargs.setdefault("ensure_ascii", False)
|
|
61
|
+
kwargs.setdefault("indent", 4)
|
|
62
|
+
kwargs.setdefault("sort_keys", True)
|
|
63
|
+
try:
|
|
64
|
+
payload = json.dumps(
|
|
65
|
+
data,
|
|
66
|
+
**kwargs,
|
|
67
|
+
)
|
|
68
|
+
return payload.encode(encoding)
|
|
69
|
+
except Exception as e:
|
|
70
|
+
msg = f"Failed to serialize data: {e}"
|
|
71
|
+
raise SerialiserFailedError(msg) from e
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Tests for serialiser modules
|
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
from io import BytesIO
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from xfintech.serde.common.dataformat import DataFormat
|
|
7
|
+
from xfintech.serde.common.error import (
|
|
8
|
+
SerialiserFailedError,
|
|
9
|
+
SerialiserInputTypeError,
|
|
10
|
+
)
|
|
11
|
+
from xfintech.serde.serialiser.pandas import PandasSerialiser
|
|
12
|
+
|
|
13
|
+
# ==================== Class Structure Tests ====================
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_pandasserialiser_has_serialise_method():
|
|
17
|
+
"""Test PandasSerialiser has serialise method"""
|
|
18
|
+
assert hasattr(PandasSerialiser, "serialise")
|
|
19
|
+
assert callable(PandasSerialiser.serialise)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_pandasserialiser_has_to_parquet_method():
|
|
23
|
+
"""Test PandasSerialiser has to_parquet method"""
|
|
24
|
+
assert hasattr(PandasSerialiser, "to_parquet")
|
|
25
|
+
assert callable(PandasSerialiser.to_parquet)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_pandasserialiser_has_to_csv_method():
|
|
29
|
+
"""Test PandasSerialiser has to_csv method"""
|
|
30
|
+
assert hasattr(PandasSerialiser, "to_csv")
|
|
31
|
+
assert callable(PandasSerialiser.to_csv)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_pandasserialiser_has_to_json_method():
|
|
35
|
+
"""Test PandasSerialiser has to_json method"""
|
|
36
|
+
assert hasattr(PandasSerialiser, "to_json")
|
|
37
|
+
assert callable(PandasSerialiser.to_json)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_pandasserialiser_methods_are_static():
|
|
41
|
+
"""Test all methods are static methods"""
|
|
42
|
+
assert isinstance(PandasSerialiser.__dict__["serialise"], staticmethod)
|
|
43
|
+
assert isinstance(PandasSerialiser.__dict__["to_parquet"], staticmethod)
|
|
44
|
+
assert isinstance(PandasSerialiser.__dict__["to_csv"], staticmethod)
|
|
45
|
+
assert isinstance(PandasSerialiser.__dict__["to_json"], staticmethod)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# ==================== serialise() Method Tests ====================
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_serialise_with_parquet_format_enum():
|
|
52
|
+
"""Test serialise with PARQUET DataFormat enum"""
|
|
53
|
+
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
|
54
|
+
result = PandasSerialiser.serialise(df, DataFormat.PARQUET)
|
|
55
|
+
assert isinstance(result, bytes)
|
|
56
|
+
assert len(result) > 0
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_serialise_with_parquet_format_string():
|
|
60
|
+
"""Test serialise with 'parquet' string"""
|
|
61
|
+
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
|
62
|
+
result = PandasSerialiser.serialise(df, "parquet")
|
|
63
|
+
assert isinstance(result, bytes)
|
|
64
|
+
assert len(result) > 0
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_serialise_with_csv_format_enum():
|
|
68
|
+
"""Test serialise with CSV DataFormat enum"""
|
|
69
|
+
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
|
70
|
+
result = PandasSerialiser.serialise(df, DataFormat.CSV)
|
|
71
|
+
assert isinstance(result, bytes)
|
|
72
|
+
assert b"a,b" in result
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_serialise_with_csv_format_string():
|
|
76
|
+
"""Test serialise with 'csv' string"""
|
|
77
|
+
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
|
78
|
+
result = PandasSerialiser.serialise(df, "csv")
|
|
79
|
+
assert isinstance(result, bytes)
|
|
80
|
+
assert b"a,b" in result
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_serialise_with_json_format_enum():
|
|
84
|
+
"""Test serialise with JSON DataFormat enum"""
|
|
85
|
+
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
|
86
|
+
result = PandasSerialiser.serialise(df, DataFormat.JSON)
|
|
87
|
+
assert isinstance(result, bytes)
|
|
88
|
+
assert b"a" in result and b"b" in result
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_serialise_with_json_format_string():
|
|
92
|
+
"""Test serialise with 'json' string"""
|
|
93
|
+
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
|
94
|
+
result = PandasSerialiser.serialise(df, "json")
|
|
95
|
+
assert isinstance(result, bytes)
|
|
96
|
+
assert b"a" in result and b"b" in result
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_serialise_with_uppercase_format_string():
|
|
100
|
+
"""Test serialise with uppercase format string"""
|
|
101
|
+
df = pd.DataFrame({"a": [1, 2]})
|
|
102
|
+
result = PandasSerialiser.serialise(df, "PARQUET")
|
|
103
|
+
assert isinstance(result, bytes)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_serialise_with_mixed_case_format_string():
|
|
107
|
+
"""Test serialise with mixed case format string"""
|
|
108
|
+
df = pd.DataFrame({"a": [1, 2]})
|
|
109
|
+
result = PandasSerialiser.serialise(df, "CsV")
|
|
110
|
+
assert isinstance(result, bytes)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_serialise_raises_on_non_dataframe():
|
|
114
|
+
"""Test serialise raises error for non-DataFrame input"""
|
|
115
|
+
with pytest.raises(SerialiserInputTypeError) as exc_info:
|
|
116
|
+
PandasSerialiser.serialise([1, 2, 3], DataFormat.PARQUET)
|
|
117
|
+
assert "expects pd.DataFrame" in str(exc_info.value)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_serialise_raises_on_dict_input():
|
|
121
|
+
"""Test serialise raises error for dict input"""
|
|
122
|
+
with pytest.raises(SerialiserInputTypeError):
|
|
123
|
+
PandasSerialiser.serialise({"a": [1, 2]}, DataFormat.CSV)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_serialise_raises_on_string_input():
|
|
127
|
+
"""Test serialise raises error for string input"""
|
|
128
|
+
with pytest.raises(SerialiserInputTypeError):
|
|
129
|
+
PandasSerialiser.serialise("not a dataframe", DataFormat.JSON)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_serialise_raises_on_none_input():
|
|
133
|
+
"""Test serialise raises error for None input"""
|
|
134
|
+
with pytest.raises(SerialiserInputTypeError):
|
|
135
|
+
PandasSerialiser.serialise(None, DataFormat.PARQUET)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_serialise_raises_on_unsupported_format():
|
|
139
|
+
"""Test serialise raises error for unsupported format"""
|
|
140
|
+
df = pd.DataFrame({"a": [1, 2]})
|
|
141
|
+
with pytest.raises(ValueError) as exc_info:
|
|
142
|
+
PandasSerialiser.serialise(df, "xml")
|
|
143
|
+
assert "Unknown DataFormat" in str(exc_info.value)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def test_serialise_empty_dataframe():
|
|
147
|
+
"""Test serialise with empty DataFrame"""
|
|
148
|
+
df = pd.DataFrame()
|
|
149
|
+
result = PandasSerialiser.serialise(df, DataFormat.CSV)
|
|
150
|
+
assert isinstance(result, bytes)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_serialise_single_column_dataframe():
|
|
154
|
+
"""Test serialise with single column DataFrame"""
|
|
155
|
+
df = pd.DataFrame({"x": [1, 2, 3]})
|
|
156
|
+
result = PandasSerialiser.serialise(df, DataFormat.JSON)
|
|
157
|
+
assert isinstance(result, bytes)
|
|
158
|
+
assert b"x" in result
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_serialise_large_dataframe():
|
|
162
|
+
"""Test serialise with large DataFrame"""
|
|
163
|
+
df = pd.DataFrame({"col": range(10000)})
|
|
164
|
+
result = PandasSerialiser.serialise(df, DataFormat.PARQUET)
|
|
165
|
+
assert isinstance(result, bytes)
|
|
166
|
+
assert len(result) > 0
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# ==================== to_parquet() Method Tests ====================
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def test_to_parquet_basic():
|
|
173
|
+
"""Test to_parquet with basic DataFrame"""
|
|
174
|
+
df = pd.DataFrame({"a": [1, 2, 3], "b": ["x", "y", "z"]})
|
|
175
|
+
result = PandasSerialiser.to_parquet(df)
|
|
176
|
+
assert isinstance(result, bytes)
|
|
177
|
+
assert len(result) > 0
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def test_to_parquet_returns_valid_parquet_bytes():
|
|
181
|
+
"""Test to_parquet returns valid parquet that can be read back"""
|
|
182
|
+
df = pd.DataFrame({"col1": [1, 2, 3], "col2": [4.5, 5.6, 6.7]})
|
|
183
|
+
result = PandasSerialiser.to_parquet(df)
|
|
184
|
+
|
|
185
|
+
# Verify it can be read back
|
|
186
|
+
buffer = BytesIO(result)
|
|
187
|
+
df_read = pd.read_parquet(buffer)
|
|
188
|
+
assert df.equals(df_read)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def test_to_parquet_with_compression():
|
|
192
|
+
"""Test to_parquet with compression argument"""
|
|
193
|
+
df = pd.DataFrame({"a": range(100)})
|
|
194
|
+
result = PandasSerialiser.to_parquet(df, compression="gzip")
|
|
195
|
+
assert isinstance(result, bytes)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def test_to_parquet_with_index():
|
|
199
|
+
"""Test to_parquet with index parameter"""
|
|
200
|
+
df = pd.DataFrame({"a": [1, 2, 3]})
|
|
201
|
+
result = PandasSerialiser.to_parquet(df, index=True)
|
|
202
|
+
assert isinstance(result, bytes)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def test_to_parquet_without_index():
|
|
206
|
+
"""Test to_parquet without index"""
|
|
207
|
+
df = pd.DataFrame({"a": [1, 2, 3]})
|
|
208
|
+
result = PandasSerialiser.to_parquet(df, index=False)
|
|
209
|
+
assert isinstance(result, bytes)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def test_to_parquet_raises_on_non_dataframe():
|
|
213
|
+
"""Test to_parquet raises error for non-DataFrame"""
|
|
214
|
+
with pytest.raises(SerialiserFailedError):
|
|
215
|
+
PandasSerialiser.to_parquet({"a": [1, 2]})
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def test_to_parquet_with_datetime_column():
|
|
219
|
+
"""Test to_parquet with datetime column"""
|
|
220
|
+
df = pd.DataFrame({"date": pd.date_range("2024-01-01", periods=3)})
|
|
221
|
+
result = PandasSerialiser.to_parquet(df)
|
|
222
|
+
assert isinstance(result, bytes)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def test_to_parquet_with_mixed_types():
|
|
226
|
+
"""Test to_parquet with mixed data types"""
|
|
227
|
+
df = pd.DataFrame({"int": [1, 2, 3], "float": [1.1, 2.2, 3.3], "str": ["a", "b", "c"], "bool": [True, False, True]})
|
|
228
|
+
result = PandasSerialiser.to_parquet(df)
|
|
229
|
+
assert isinstance(result, bytes)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
# ==================== to_csv() Method Tests ====================
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def test_to_csv_basic():
|
|
236
|
+
"""Test to_csv with basic DataFrame"""
|
|
237
|
+
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
|
238
|
+
result = PandasSerialiser.to_csv(df)
|
|
239
|
+
assert isinstance(result, bytes)
|
|
240
|
+
assert b"a,b" in result
|
|
241
|
+
assert b"1,4" in result
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def test_to_csv_returns_valid_csv_bytes():
|
|
245
|
+
"""Test to_csv returns valid CSV that can be read back"""
|
|
246
|
+
df = pd.DataFrame({"col1": [1, 2, 3], "col2": [4, 5, 6]})
|
|
247
|
+
result = PandasSerialiser.to_csv(df, index=False)
|
|
248
|
+
|
|
249
|
+
# Verify it's proper CSV format
|
|
250
|
+
text = result.decode("utf-8")
|
|
251
|
+
assert "col1,col2" in text
|
|
252
|
+
assert "1,4" in text
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def test_to_csv_with_index():
|
|
256
|
+
"""Test to_csv with index included"""
|
|
257
|
+
df = pd.DataFrame({"a": [1, 2, 3]})
|
|
258
|
+
result = PandasSerialiser.to_csv(df, index=True)
|
|
259
|
+
assert isinstance(result, bytes)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def test_to_csv_without_index():
|
|
263
|
+
"""Test to_csv without index"""
|
|
264
|
+
df = pd.DataFrame({"a": [1, 2, 3]})
|
|
265
|
+
result = PandasSerialiser.to_csv(df, index=False)
|
|
266
|
+
text = result.decode("utf-8")
|
|
267
|
+
assert text.startswith("a\n") or text.startswith("a\r\n")
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def test_to_csv_with_custom_encoding():
|
|
271
|
+
"""Test to_csv with custom encoding"""
|
|
272
|
+
df = pd.DataFrame({"a": ["中文", "日本語"]})
|
|
273
|
+
result = PandasSerialiser.to_csv(df, encoding="utf-8")
|
|
274
|
+
assert isinstance(result, bytes)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def test_to_csv_with_custom_separator():
|
|
278
|
+
"""Test to_csv with custom separator"""
|
|
279
|
+
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
|
280
|
+
result = PandasSerialiser.to_csv(df, sep="|")
|
|
281
|
+
assert b"|" in result
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def test_to_csv_raises_on_non_dataframe():
|
|
285
|
+
"""Test to_csv raises error for non-DataFrame"""
|
|
286
|
+
with pytest.raises(SerialiserFailedError):
|
|
287
|
+
PandasSerialiser.to_csv([1, 2, 3])
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def test_to_csv_empty_dataframe():
|
|
291
|
+
"""Test to_csv with empty DataFrame"""
|
|
292
|
+
df = pd.DataFrame()
|
|
293
|
+
result = PandasSerialiser.to_csv(df)
|
|
294
|
+
assert isinstance(result, bytes)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def test_to_csv_with_na_values():
|
|
298
|
+
"""Test to_csv with NA values"""
|
|
299
|
+
df = pd.DataFrame({"a": [1, None, 3], "b": [4, 5, None]})
|
|
300
|
+
result = PandasSerialiser.to_csv(df)
|
|
301
|
+
assert isinstance(result, bytes)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def test_to_csv_with_header_false():
|
|
305
|
+
"""Test to_csv without header"""
|
|
306
|
+
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
|
307
|
+
result = PandasSerialiser.to_csv(df, header=False, index=False)
|
|
308
|
+
text = result.decode("utf-8")
|
|
309
|
+
assert "a,b" not in text
|
|
310
|
+
assert "1,3" in text
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
# ==================== to_json() Method Tests ====================
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def test_to_json_basic():
|
|
317
|
+
"""Test to_json with basic DataFrame"""
|
|
318
|
+
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
|
319
|
+
result = PandasSerialiser.to_json(df)
|
|
320
|
+
assert isinstance(result, bytes)
|
|
321
|
+
assert b"a" in result and b"b" in result
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def test_to_json_returns_valid_json_bytes():
|
|
325
|
+
"""Test to_json returns valid JSON"""
|
|
326
|
+
df = pd.DataFrame({"col1": [1, 2], "col2": [3, 4]})
|
|
327
|
+
result = PandasSerialiser.to_json(df, orient="records")
|
|
328
|
+
|
|
329
|
+
# Verify it's valid JSON
|
|
330
|
+
import json
|
|
331
|
+
|
|
332
|
+
text = result.decode("utf-8")
|
|
333
|
+
parsed = json.loads(text)
|
|
334
|
+
assert isinstance(parsed, list)
|
|
335
|
+
assert len(parsed) == 2
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def test_to_json_with_orient_records():
|
|
339
|
+
"""Test to_json with orient='records'"""
|
|
340
|
+
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
|
341
|
+
result = PandasSerialiser.to_json(df, orient="records")
|
|
342
|
+
assert isinstance(result, bytes)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def test_to_json_with_orient_split():
|
|
346
|
+
"""Test to_json with orient='split'"""
|
|
347
|
+
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
|
348
|
+
result = PandasSerialiser.to_json(df, orient="split")
|
|
349
|
+
assert isinstance(result, bytes)
|
|
350
|
+
assert b"columns" in result and b"data" in result
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def test_to_json_with_orient_index():
|
|
354
|
+
"""Test to_json with orient='index'"""
|
|
355
|
+
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
|
356
|
+
result = PandasSerialiser.to_json(df, orient="index")
|
|
357
|
+
assert isinstance(result, bytes)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def test_to_json_with_orient_columns():
|
|
361
|
+
"""Test to_json with orient='columns'"""
|
|
362
|
+
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
|
363
|
+
result = PandasSerialiser.to_json(df, orient="columns")
|
|
364
|
+
assert isinstance(result, bytes)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def test_to_json_with_orient_values():
|
|
368
|
+
"""Test to_json with orient='values'"""
|
|
369
|
+
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
|
370
|
+
result = PandasSerialiser.to_json(df, orient="values")
|
|
371
|
+
assert isinstance(result, bytes)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def test_to_json_with_custom_encoding():
|
|
375
|
+
"""Test to_json with custom encoding"""
|
|
376
|
+
df = pd.DataFrame({"a": [1, 2]})
|
|
377
|
+
result = PandasSerialiser.to_json(df, encoding="utf-8")
|
|
378
|
+
assert isinstance(result, bytes)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def test_to_json_raises_on_non_dataframe():
|
|
382
|
+
"""Test to_json raises error for non-DataFrame"""
|
|
383
|
+
with pytest.raises(SerialiserFailedError):
|
|
384
|
+
PandasSerialiser.to_json({"a": [1, 2]})
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def test_to_json_empty_dataframe():
|
|
388
|
+
"""Test to_json with empty DataFrame"""
|
|
389
|
+
df = pd.DataFrame()
|
|
390
|
+
result = PandasSerialiser.to_json(df)
|
|
391
|
+
assert isinstance(result, bytes)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def test_to_json_with_datetime():
|
|
395
|
+
"""Test to_json with datetime values"""
|
|
396
|
+
df = pd.DataFrame({"date": pd.date_range("2024-01-01", periods=2)})
|
|
397
|
+
result = PandasSerialiser.to_json(df)
|
|
398
|
+
assert isinstance(result, bytes)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def test_to_json_with_lines_format():
|
|
402
|
+
"""Test to_json with lines=True (newline-delimited JSON)"""
|
|
403
|
+
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
|
404
|
+
result = PandasSerialiser.to_json(df, orient="records", lines=True)
|
|
405
|
+
assert isinstance(result, bytes)
|
|
406
|
+
text = result.decode("utf-8")
|
|
407
|
+
lines = text.strip().split("\n")
|
|
408
|
+
assert len(lines) == 2
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
# ==================== Integration and Edge Case Tests ====================
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def test_serialise_all_formats_produce_bytes():
|
|
415
|
+
"""Test all formats produce bytes output"""
|
|
416
|
+
df = pd.DataFrame({"a": [1, 2, 3]})
|
|
417
|
+
|
|
418
|
+
for format in [DataFormat.PARQUET, DataFormat.CSV, DataFormat.JSON]:
|
|
419
|
+
result = PandasSerialiser.serialise(df, format)
|
|
420
|
+
assert isinstance(result, bytes)
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
def test_serialise_same_dataframe_multiple_times():
|
|
424
|
+
"""Test serialising same DataFrame multiple times produces consistent results"""
|
|
425
|
+
df = pd.DataFrame({"a": [1, 2, 3]})
|
|
426
|
+
result1 = PandasSerialiser.serialise(df, DataFormat.CSV, index=False)
|
|
427
|
+
result2 = PandasSerialiser.serialise(df, DataFormat.CSV, index=False)
|
|
428
|
+
assert result1 == result2
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def test_dataframe_with_special_characters():
|
|
432
|
+
"""Test DataFrame with special characters in values"""
|
|
433
|
+
df = pd.DataFrame({"col": ["test,with,comma", "test\nwith\nnewline", 'test"quote"']})
|
|
434
|
+
result = PandasSerialiser.to_csv(df)
|
|
435
|
+
assert isinstance(result, bytes)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def test_dataframe_with_unicode():
|
|
439
|
+
"""Test DataFrame with Unicode characters"""
|
|
440
|
+
df = pd.DataFrame({"text": ["Hello 世界", "Привет", "مرحبا"]})
|
|
441
|
+
for format in [DataFormat.CSV, DataFormat.JSON]:
|
|
442
|
+
result = PandasSerialiser.serialise(df, format)
|
|
443
|
+
assert isinstance(result, bytes)
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def test_dataframe_with_large_strings():
|
|
447
|
+
"""Test DataFrame with large string values"""
|
|
448
|
+
df = pd.DataFrame({"text": ["x" * 10000]})
|
|
449
|
+
result = PandasSerialiser.serialise(df, DataFormat.PARQUET)
|
|
450
|
+
assert isinstance(result, bytes)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def test_serialise_with_kwargs_passthrough():
|
|
454
|
+
"""Test that kwargs are passed through to underlying methods"""
|
|
455
|
+
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
|
456
|
+
result = PandasSerialiser.serialise(df, DataFormat.CSV, index=False, sep="|")
|
|
457
|
+
assert b"|" in result
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def test_multiindex_dataframe():
|
|
461
|
+
"""Test serialising DataFrame with MultiIndex"""
|
|
462
|
+
arrays = [["A", "A", "B", "B"], [1, 2, 1, 2]]
|
|
463
|
+
index = pd.MultiIndex.from_arrays(arrays, names=["letter", "number"])
|
|
464
|
+
df = pd.DataFrame({"value": [10, 20, 30, 40]}, index=index)
|
|
465
|
+
|
|
466
|
+
result = PandasSerialiser.to_parquet(df)
|
|
467
|
+
assert isinstance(result, bytes)
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def test_dataframe_with_categorical_data():
|
|
471
|
+
"""Test DataFrame with categorical data"""
|
|
472
|
+
df = pd.DataFrame({"cat": pd.Categorical(["a", "b", "c", "a"])})
|
|
473
|
+
result = PandasSerialiser.to_parquet(df)
|
|
474
|
+
assert isinstance(result, bytes)
|