cfquant 0.2.22__tar.gz → 0.2.24__tar.gz
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.
- {cfquant-0.2.22 → cfquant-0.2.24}/PKG-INFO +1 -1
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/_editable_install.py +41 -8
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/16_/345/220/257/345/212/250/345/256/211/350/243/205/346/265/213/350/257/225.py +49 -3
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_project_updater.py +1 -1
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/version.py +1 -1
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant.egg-info/PKG-INFO +1 -1
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant_web_server.py +2 -17
- {cfquant-0.2.22 → cfquant-0.2.24}/pyproject.toml +1 -1
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/app.js +4 -7
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/index.html +2 -2
- {cfquant-0.2.22 → cfquant-0.2.24}/LICENSE +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/LTtx/__init__.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/LTtx/tx/Config.txt +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/LTtx/tx/LTtx_server.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/LTtx/tx/__init__.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/LTtx/tx/tx.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/MANIFEST.in +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/README.md +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/__init__.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/account_routing.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/batch_orders.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/cftrader.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/channels.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/cli.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/client.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/config.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/hub.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/level2.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/logging_i18n.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/normal_bridge.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/order_meta.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/pipe_bridge.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/pipe_client.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/pipe_hub.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/pipe_transport.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/protocol.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/qmt_bridge.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/qmt_strategy_deploy.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/qmt_strategy_package.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/qmt_strategy_runtime.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/runtime_report.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/10_/345/221/275/344/273/244/350/241/214/346/216/245/345/217/243/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/11_/346/231/256/351/200/232/346/241/245/346/216/245/346/264/276/345/217/221/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/12_/350/256/242/345/215/225/345/244/207/346/263/250/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/13_/347/256/241/351/201/223/344/270/255/345/277/203/350/277/236/346/216/245/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/14_/350/277/220/350/241/214/346/227/266/346/212/245/345/221/212/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/15_/347/275/221/351/241/265/347/212/266/346/200/201/347/274/223/345/255/230/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/17_/345/244/247QMT/346/216/245/345/217/243/351/200/202/351/205/215/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/18_/351/253/230/347/272/247/346/250/241/345/274/217/345/256/236/346/234/272/350/201/224/350/260/203.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/19_/345/256/236/346/234/272/350/201/224/350/260/203/345/210/244/345/256/232/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/1_/350/241/214/346/203/205/346/216/245/346/224/266/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/20_/350/201/224/350/260/203/351/227/256/351/242/230/344/277/256/345/244/215/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/21_/345/215/225/350/202/241/350/241/214/346/203/205/350/256/242/351/230/205/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/22_/350/277/236/346/216/245/350/257/212/346/226/255/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/23_/347/244/272/344/276/213/351/205/215/347/275/256/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/24_/350/264/246/346/210/267/347/274/223/345/255/230/346/214/211/351/234/200/345/210/267/346/226/260/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/25_/350/264/246/346/210/267/347/274/223/345/255/230/351/241/265/351/235/242/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/26_/345/205/250/346/216/250/350/256/242/351/230/205/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/27_/345/205/250/346/216/250/350/256/242/351/230/205/351/241/265/351/235/242/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/28_Level2/346/216/245/345/217/243/351/200/202/351/205/215/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/29_Level2/350/241/214/346/203/205/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/2_/346/225/260/346/215/256/350/216/267/345/217/226/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/30_cftrader/346/211/271/351/207/217/344/270/213/345/215/225/346/200/247/350/203/275/345/237/272/345/207/206.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/31_cftrader/346/250/241/346/213/237/350/264/246/345/217/267/346/211/271/351/207/217/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/3_/346/225/260/346/215/256/344/270/213/350/275/275/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/4_/344/272/244/346/230/223/345/247/224/346/211/230/346/237/245/350/257/242/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/5_/347/234/237/345/256/236/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/6_/345/233/236/350/260/203/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/7_/345/220/214/346/255/245/345/274/202/346/255/245/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/8_/346/210/220/344/272/244/350/256/242/345/215/225/345/222/214/345/247/224/346/211/230/350/256/242/345/215/225/346/237/245/350/257/242/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/9_/345/217/257/346/222/244/350/256/242/345/215/225/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/_helpers.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/log/cftrader/346/250/241/346/213/237/350/264/246/345/217/267/346/211/271/351/207/217/344/270/213/345/215/225/346/265/213/350/257/225_20260911_024617.md" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/readme.md +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_api_tester_browser.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_api_tester_web.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_binding_delete_confirmation.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_cftrader.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_cftrader_tutorial.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_cftrader_web.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_credit_compat.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_json_serialization.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_python_api_reference.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_qmt_strategy_browser.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_qmt_strategy_deploy.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_qmt_strategy_web.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_tutorial_reader.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tests/test_tx_auto_import.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tx.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/tx_trade_bridge.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/xtconstant.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/xtdata.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/xttrader.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant/xttype.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant.egg-info/SOURCES.txt +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant.egg-info/dependency_links.txt +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant.egg-info/entry_points.txt +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant.egg-info/requires.txt +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant.egg-info/top_level.txt +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/cfquant_pipe_hub.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts/CFQUANT.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts/CFQUANT_CTYPE_ALL_LOWLAT.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts/CFQUANT_LITE.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts/CFQUANT_TRADE_LOWLAT.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts/__init__.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_CTYPE_ALL_LOWLAT_SH.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_CTYPE_ALL_LOWLAT_SZ.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_LITE_SH.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_LITE_SZ.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_TRADE_LOWLAT_SH.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_TRADE_LOWLAT_SZ.py" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/readme.md" +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/requirements.txt +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/setup.cfg +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/__init__.py +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/api-tester.js +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/avatars/amber-pulse.svg +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/avatars/copper-grid.svg +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/avatars/market-blue.svg +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/avatars/rose-circuit.svg +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/avatars/signal-green.svg +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/avatars/slate-wave.svg +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/avatars/teal-orbit.svg +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/avatars/violet-node.svg +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/cftrader-api-data.js +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/favicon.svg +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-10.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-11.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-12.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-13.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-14.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-15.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-16.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-17.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-18.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-19.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-20.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-21.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-4.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-5.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-6.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-7.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-8.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/image/qmt_deploy/image-9.png +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/python-api-data.js +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/python-api.js +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/styles.css +0 -0
- {cfquant-0.2.22 → cfquant-0.2.24}/web_dashboard/vendor/mermaid.min.js +0 -0
|
@@ -114,7 +114,7 @@ def _run_pip_command(
|
|
|
114
114
|
):
|
|
115
115
|
kwargs = {
|
|
116
116
|
"cwd": str(project_root),
|
|
117
|
-
"env":
|
|
117
|
+
"env": pip_environment(),
|
|
118
118
|
"stdout": subprocess.PIPE,
|
|
119
119
|
"stderr": subprocess.STDOUT,
|
|
120
120
|
"text": True,
|
|
@@ -318,7 +318,7 @@ def run_editable_install(
|
|
|
318
318
|
})
|
|
319
319
|
kwargs = {
|
|
320
320
|
"cwd": str(project_root),
|
|
321
|
-
"env":
|
|
321
|
+
"env": pip_environment(),
|
|
322
322
|
"stdout": subprocess.PIPE,
|
|
323
323
|
"stderr": subprocess.STDOUT,
|
|
324
324
|
"text": True,
|
|
@@ -413,6 +413,15 @@ def python_environment(clear_pythonpath=False):
|
|
|
413
413
|
return env
|
|
414
414
|
|
|
415
415
|
|
|
416
|
+
def pip_environment():
|
|
417
|
+
env = python_environment(clear_pythonpath=True)
|
|
418
|
+
# Legacy Windows egg-link files use the system encoding, not UTF-8.
|
|
419
|
+
if sys.platform == "win32":
|
|
420
|
+
env["PYTHONUTF8"] = "0"
|
|
421
|
+
env["PYTHONIOENCODING"] = "utf-8"
|
|
422
|
+
return env
|
|
423
|
+
|
|
424
|
+
|
|
416
425
|
def neutral_check_cwd():
|
|
417
426
|
return Path(tempfile.gettempdir()).resolve()
|
|
418
427
|
|
|
@@ -423,7 +432,8 @@ def run(args, cwd, quiet=False, clear_pythonpath=False):
|
|
|
423
432
|
return subprocess.run(
|
|
424
433
|
list(args),
|
|
425
434
|
cwd=str(cwd),
|
|
426
|
-
env=
|
|
435
|
+
env=(pip_environment() if list(args)[1:3] == ["-m", "pip"]
|
|
436
|
+
else python_environment(clear_pythonpath=clear_pythonpath)),
|
|
427
437
|
stdout=stdout,
|
|
428
438
|
stderr=stderr,
|
|
429
439
|
)
|
|
@@ -441,6 +451,27 @@ def is_cfquant_installed(python_exe=None):
|
|
|
441
451
|
return completed.returncode == 0
|
|
442
452
|
|
|
443
453
|
|
|
454
|
+
def project_package_version(project_root):
|
|
455
|
+
try:
|
|
456
|
+
import tomllib
|
|
457
|
+
except ImportError:
|
|
458
|
+
from pip._vendor import tomli as tomllib
|
|
459
|
+
with (Path(project_root) / "pyproject.toml").open("rb") as stream:
|
|
460
|
+
return str(tomllib.load(stream)["project"]["version"])
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def installed_package_version(python_exe=None):
|
|
464
|
+
completed = subprocess.run(
|
|
465
|
+
[python_exe or sys.executable, "-c",
|
|
466
|
+
"from importlib.metadata import version; print(version('cfquant'))"],
|
|
467
|
+
cwd=str(neutral_check_cwd()),
|
|
468
|
+
env=python_environment(clear_pythonpath=True),
|
|
469
|
+
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
470
|
+
text=True, encoding="utf-8", timeout=30,
|
|
471
|
+
)
|
|
472
|
+
return completed.stdout.strip() if completed.returncode == 0 else ""
|
|
473
|
+
|
|
474
|
+
|
|
444
475
|
def ensure_cfquant_installed(project_root, python_exe=None):
|
|
445
476
|
project_root = Path(project_root).resolve()
|
|
446
477
|
if not (project_root / "pyproject.toml").is_file():
|
|
@@ -448,9 +479,11 @@ def ensure_cfquant_installed(project_root, python_exe=None):
|
|
|
448
479
|
return 2
|
|
449
480
|
|
|
450
481
|
python_exe = python_exe or sys.executable
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
482
|
+
expected = project_package_version(project_root)
|
|
483
|
+
installed = installed_package_version(python_exe)
|
|
484
|
+
print("cfquant installed=%s project=%s" % (installed or "missing", expected))
|
|
485
|
+
if installed == expected:
|
|
486
|
+
print("Package versions match; skip installation.")
|
|
454
487
|
return 0
|
|
455
488
|
|
|
456
489
|
command = editable_install_args(project_root, python_exe)
|
|
@@ -470,8 +503,8 @@ def ensure_cfquant_installed(project_root, python_exe=None):
|
|
|
470
503
|
print("[ERROR] source install failed with exit code %s." % completed.returncode, file=sys.stderr)
|
|
471
504
|
return completed.returncode
|
|
472
505
|
|
|
473
|
-
if
|
|
474
|
-
print("[ERROR]
|
|
506
|
+
if installed_package_version(python_exe) != expected:
|
|
507
|
+
print("[ERROR] Installed cfquant version does not match the project after installation.", file=sys.stderr)
|
|
475
508
|
return 1
|
|
476
509
|
print("%s package is installed." % PACKAGE_NAME)
|
|
477
510
|
return 0
|
|
@@ -1,12 +1,44 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
import json
|
|
3
3
|
import subprocess
|
|
4
|
+
import sys
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
7
|
+
import pytest
|
|
6
8
|
from cfquant import _editable_install
|
|
7
9
|
from cfquant import cli
|
|
8
10
|
|
|
9
11
|
|
|
12
|
+
def test_pip_environment_preserves_parent_settings(monkeypatch):
|
|
13
|
+
monkeypatch.setenv("PYTHONUTF8", "1")
|
|
14
|
+
monkeypatch.setenv("PYTHONPATH", "inherited-source")
|
|
15
|
+
monkeypatch.setattr(sys, "platform", "win32")
|
|
16
|
+
env = _editable_install.pip_environment()
|
|
17
|
+
assert env["PYTHONUTF8"] == "0"
|
|
18
|
+
assert env["PYTHONIOENCODING"] == "utf-8"
|
|
19
|
+
assert "PYTHONPATH" not in env
|
|
20
|
+
assert _editable_install.os.environ["PYTHONUTF8"] == "1"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.mark.skipif(sys.platform != "win32", reason="Windows legacy encoding")
|
|
24
|
+
def test_pip_scans_legacy_egg_link_without_modifying_it(tmp_path):
|
|
25
|
+
target = tmp_path / "\u79c1\u4eba\u6587\u4ef6"
|
|
26
|
+
try:
|
|
27
|
+
contents = (str(target) + "\n").encode("mbcs")
|
|
28
|
+
except UnicodeEncodeError:
|
|
29
|
+
pytest.skip("System encoding cannot represent the fixture path")
|
|
30
|
+
target.mkdir()
|
|
31
|
+
link = tmp_path / "legacy.egg-link"
|
|
32
|
+
link.write_bytes(contents)
|
|
33
|
+
result = _editable_install._run_pip_command(
|
|
34
|
+
[sys.executable, "-m", "pip", "list", "--path", str(tmp_path),
|
|
35
|
+
"--format=json", "--disable-pip-version-check"],
|
|
36
|
+
tmp_path,
|
|
37
|
+
)
|
|
38
|
+
assert result["ok"], result["output"]
|
|
39
|
+
assert link.read_bytes() == contents
|
|
40
|
+
|
|
41
|
+
|
|
10
42
|
def test_editable_install_uses_split_arguments(tmp_path):
|
|
11
43
|
command = _editable_install.editable_install_args(tmp_path, python_exe="python")
|
|
12
44
|
|
|
@@ -260,8 +292,8 @@ def test_run_editable_install_falls_back_to_source_install(monkeypatch, tmp_path
|
|
|
260
292
|
|
|
261
293
|
|
|
262
294
|
def test_ensure_cfquant_installed_falls_back_to_source_install(monkeypatch, tmp_path):
|
|
263
|
-
(tmp_path / "pyproject.toml").write_text("[project]\nname = 'cfquant'\n", encoding="utf-8")
|
|
264
|
-
installed_checks = [
|
|
295
|
+
(tmp_path / "pyproject.toml").write_text("[project]\nname = 'cfquant'\nversion = '0.2.23'\n", encoding="utf-8")
|
|
296
|
+
installed_checks = ["0.2.22", "0.2.23"]
|
|
265
297
|
calls = []
|
|
266
298
|
|
|
267
299
|
def fake_is_installed(python_exe=None):
|
|
@@ -277,7 +309,7 @@ def test_ensure_cfquant_installed_falls_back_to_source_install(monkeypatch, tmp_
|
|
|
277
309
|
result.returncode = 7 if "--editable" in args else 0
|
|
278
310
|
return result
|
|
279
311
|
|
|
280
|
-
monkeypatch.setattr(_editable_install, "
|
|
312
|
+
monkeypatch.setattr(_editable_install, "installed_package_version", fake_is_installed)
|
|
281
313
|
monkeypatch.setattr(_editable_install, "run", fake_run)
|
|
282
314
|
|
|
283
315
|
assert _editable_install.ensure_cfquant_installed(tmp_path, python_exe="python") == 0
|
|
@@ -286,6 +318,20 @@ def test_ensure_cfquant_installed_falls_back_to_source_install(monkeypatch, tmp_
|
|
|
286
318
|
assert calls[1][0][-1] == "."
|
|
287
319
|
|
|
288
320
|
|
|
321
|
+
@pytest.mark.parametrize("installed", ["", "0.2.22", "0.2.24", "0.2.23"])
|
|
322
|
+
def test_startup_installs_only_when_version_differs(monkeypatch, tmp_path, installed):
|
|
323
|
+
(tmp_path / "pyproject.toml").write_text("[project]\nversion='0.2.23'\n", encoding="utf-8")
|
|
324
|
+
versions = iter([installed, "0.2.23"])
|
|
325
|
+
monkeypatch.setattr(_editable_install, "installed_package_version", lambda exe: next(versions))
|
|
326
|
+
calls = []
|
|
327
|
+
def install(args, cwd):
|
|
328
|
+
calls.append(args)
|
|
329
|
+
return subprocess.CompletedProcess(args, 0)
|
|
330
|
+
monkeypatch.setattr(_editable_install, "run", install)
|
|
331
|
+
assert _editable_install.ensure_cfquant_installed(tmp_path, "python") == 0
|
|
332
|
+
assert len(calls) == (0 if installed == "0.2.23" else 1)
|
|
333
|
+
|
|
334
|
+
|
|
289
335
|
def test_start_script_passes_dot_not_trailing_dp0():
|
|
290
336
|
script = (Path(__file__).resolve().parents[2] / "start_cfquant.bat").read_text(encoding="utf-8")
|
|
291
337
|
|
|
@@ -36,7 +36,7 @@ def project_updater(tmp_path, monkeypatch):
|
|
|
36
36
|
monkeypatch.setattr(
|
|
37
37
|
updater,
|
|
38
38
|
"_run_editable_install",
|
|
39
|
-
lambda reason:
|
|
39
|
+
lambda reason: pytest.fail("Web updates must not run pip"),
|
|
40
40
|
)
|
|
41
41
|
monkeypatch.setattr(updater, "_require_editable_install", lambda result: None)
|
|
42
42
|
return web, updater, project_root
|
|
@@ -9038,18 +9038,11 @@ class CfquantProjectUpdater(object):
|
|
|
9038
9038
|
try:
|
|
9039
9039
|
self._set_operation_phase("restore", "正在恢复选中的项目版本")
|
|
9040
9040
|
self._restore_backup(selected)
|
|
9041
|
-
|
|
9042
|
-
editable_install = self._run_editable_install("project_rollback")
|
|
9043
|
-
self._require_editable_install(editable_install)
|
|
9041
|
+
editable_install = {"deferred": True, "attempted": False}
|
|
9044
9042
|
self._set_operation_phase("deploy", "正在同步回滚后的 cfquant 核心到 QMT 目录")
|
|
9045
9043
|
qmt_core_deploy = auto_deploy_qmt_core_for_all_accounts(source_dir=BASE_DIR)
|
|
9046
9044
|
except Exception:
|
|
9047
9045
|
self._restore_backup(rollback_backup)
|
|
9048
|
-
try:
|
|
9049
|
-
recovery_install = self._run_editable_install("project_rollback_recovery")
|
|
9050
|
-
self._require_editable_install(recovery_install)
|
|
9051
|
-
except Exception as recovery_error:
|
|
9052
|
-
safe_print("project rollback editable install recovery failed: %s" % recovery_error)
|
|
9053
9046
|
raise
|
|
9054
9047
|
self._write_rollback_meta(
|
|
9055
9048
|
selected,
|
|
@@ -9113,9 +9106,7 @@ class CfquantProjectUpdater(object):
|
|
|
9113
9106
|
shutil.copy2(src, dst)
|
|
9114
9107
|
copied.append(rel_path)
|
|
9115
9108
|
entry_info = self._entry_update_info(changed)
|
|
9116
|
-
|
|
9117
|
-
editable_install = self._run_editable_install("project_update")
|
|
9118
|
-
self._require_editable_install(editable_install)
|
|
9109
|
+
editable_install = {"deferred": True, "attempted": False}
|
|
9119
9110
|
self._set_operation_phase("deploy", "正在同步最新 cfquant 核心到 QMT 目录")
|
|
9120
9111
|
qmt_core_deploy = auto_deploy_qmt_core_for_all_accounts(source_dir=BASE_DIR)
|
|
9121
9112
|
qmt_deploy_summary = qmt_core_deploy.get("summary") or {}
|
|
@@ -9156,12 +9147,6 @@ class CfquantProjectUpdater(object):
|
|
|
9156
9147
|
}
|
|
9157
9148
|
except Exception:
|
|
9158
9149
|
self._restore_backup(backup)
|
|
9159
|
-
if editable_install and editable_install.get("attempted"):
|
|
9160
|
-
try:
|
|
9161
|
-
recovery_install = self._run_editable_install("project_update_recovery")
|
|
9162
|
-
self._require_editable_install(recovery_install)
|
|
9163
|
-
except Exception as recovery_error:
|
|
9164
|
-
safe_print("project update editable install recovery failed: %s" % recovery_error)
|
|
9165
9150
|
raise
|
|
9166
9151
|
|
|
9167
9152
|
def _run_editable_install(self, reason):
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const FRONTEND_VERSION = '
|
|
1
|
+
const FRONTEND_VERSION = 'web_20260917_03';
|
|
2
2
|
|
|
3
3
|
const state = {
|
|
4
4
|
accountId: '',
|
|
@@ -5466,8 +5466,7 @@ function qmtUpdateProgressSteps(kind) {
|
|
|
5466
5466
|
{ key: 'upload', label: '上传项目源码 zip', percent: 42 },
|
|
5467
5467
|
{ key: 'backup', label: '备份当前 Web 项目', percent: 58 },
|
|
5468
5468
|
{ key: 'install', label: '替换 Web 项目文件', percent: 82 },
|
|
5469
|
-
{ key: '
|
|
5470
|
-
{ key: 'restart', label: '重启 Web 服务', percent: 94 },
|
|
5469
|
+
{ key: 'restart', label: '重启并检查 SDK 版本', percent: 94 },
|
|
5471
5470
|
{ key: 'done', label: '更新完成', percent: 100 },
|
|
5472
5471
|
];
|
|
5473
5472
|
}
|
|
@@ -5476,8 +5475,7 @@ function qmtUpdateProgressSteps(kind) {
|
|
|
5476
5475
|
{ key: 'prepare', label: '确认 Web 回滚目标', percent: 12 },
|
|
5477
5476
|
{ key: 'backup', label: '备份当前 Web 项目', percent: 36 },
|
|
5478
5477
|
{ key: 'restore', label: '恢复选中备份', percent: 76 },
|
|
5479
|
-
{ key: '
|
|
5480
|
-
{ key: 'restart', label: '重启 Web 服务', percent: 94 },
|
|
5478
|
+
{ key: 'restart', label: '重启并检查 SDK 版本', percent: 94 },
|
|
5481
5479
|
{ key: 'done', label: '回滚完成', percent: 100 },
|
|
5482
5480
|
];
|
|
5483
5481
|
}
|
|
@@ -5487,8 +5485,7 @@ function qmtUpdateProgressSteps(kind) {
|
|
|
5487
5485
|
{ key: 'download', label: '连接官网并下载发布包', percent: 38 },
|
|
5488
5486
|
{ key: 'backup', label: '备份当前 Web 项目', percent: 58 },
|
|
5489
5487
|
{ key: 'install', label: '替换 Web 项目文件', percent: 82 },
|
|
5490
|
-
{ key: '
|
|
5491
|
-
{ key: 'restart', label: '重启 Web 服务', percent: 94 },
|
|
5488
|
+
{ key: 'restart', label: '重启并检查 SDK 版本', percent: 94 },
|
|
5492
5489
|
{ key: 'done', label: '更新完成', percent: 100 },
|
|
5493
5490
|
];
|
|
5494
5491
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>cfquant 控制台</title>
|
|
7
7
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
8
|
-
<link rel="stylesheet" href="/styles.css?v=
|
|
8
|
+
<link rel="stylesheet" href="/styles.css?v=web_20260917_03">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="webAuthOverlay" class="auth-overlay hidden" aria-live="polite">
|
|
@@ -3176,6 +3176,6 @@ else:
|
|
|
3176
3176
|
<script src="/cftrader-api-data.js?v=20260911_02"></script>
|
|
3177
3177
|
<script src="/api-tester.js?v=20260916_apikey_01"></script>
|
|
3178
3178
|
<script src="/python-api.js?v=20260911_api_test_01"></script>
|
|
3179
|
-
<script src="/app.js?v=
|
|
3179
|
+
<script src="/app.js?v=web_20260917_03"></script>
|
|
3180
3180
|
</body>
|
|
3181
3181
|
</html>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|