cfquant 0.2.56__tar.gz → 0.2.57__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.56 → cfquant-0.2.57}/PKG-INFO +2 -1
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/_editable_install.py +40 -2
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/management.py +16 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/qmt_component_agent.js +11 -2
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/qmt_component_login.py +109 -41
- cfquant-0.2.57/cfquant/qmt_update.py +366 -0
- cfquant-0.2.57/cfquant/remote_adapter.py +265 -0
- cfquant-0.2.57/cfquant/remote_management.py +407 -0
- cfquant-0.2.57/cfquant/remote_supervisor.py +120 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/16_/345/220/257/345/212/250/345/256/211/350/243/205/346/265/213/350/257/225.py +36 -1
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_qmt_auto_login_browser.py +87 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_qmt_auto_login_integration.py +121 -3
- cfquant-0.2.57/cfquant/tests/test_qmt_component_login.py +347 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_qmt_strategy_browser.py +6 -5
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_qmt_strategy_web.py +3 -3
- cfquant-0.2.57/cfquant/tests/test_qmt_update.py +74 -0
- cfquant-0.2.57/cfquant/tests/test_remote_management.py +352 -0
- cfquant-0.2.57/cfquant/tests/test_remote_management_browser.py +40 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/version.py +2 -2
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant.egg-info/PKG-INFO +2 -1
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant.egg-info/SOURCES.txt +8 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant.egg-info/requires.txt +3 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant_web_server.py +1261 -1065
- {cfquant-0.2.56 → cfquant-0.2.57}/pyproject.toml +2 -1
- {cfquant-0.2.56 → cfquant-0.2.57}/qmt_scripts/CFQUANT_LITE.py +1 -1
- {cfquant-0.2.56 → cfquant-0.2.57}/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 +1 -1
- {cfquant-0.2.56 → cfquant-0.2.57}/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 +1 -1
- {cfquant-0.2.56 → cfquant-0.2.57}/requirements.txt +2 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/app.js +66 -24
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/index.html +68 -24
- cfquant-0.2.57/web_dashboard/remote-management.js +52 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/styles.css +4 -0
- cfquant-0.2.56/cfquant/tests/test_qmt_component_login.py +0 -165
- {cfquant-0.2.56 → cfquant-0.2.57}/LICENSE +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/LTtx/__init__.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/LTtx/tx/Config.txt +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/LTtx/tx/LTtx_server.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/LTtx/tx/__init__.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/LTtx/tx/tx.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/MANIFEST.in +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/README.md +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/__init__.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/account_routing.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/batch_orders.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/build_info.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/callback_dispatcher.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/cftrader.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/channels.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/cli.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/client.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/config.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/diagnostics.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/flow_control.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/hub.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/level2.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/log_management.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/logging_i18n.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/normal_bridge.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/order_identity.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/order_meta.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/pipe_bridge.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/pipe_client.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/pipe_hub.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/pipe_transport.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/protocol.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/qmt_binding_settings.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/qmt_bridge.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/qmt_credentials.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/qmt_dependencies.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/qmt_pipe_runtime.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/qmt_strategy_deploy.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/qmt_strategy_package.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/qmt_strategy_runtime.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/quote_history.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/rpc_timing.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/runtime_report.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/stock_connect.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/cfquant/tests/29_Level2/350/241/214/346/203/205/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/cfquant/tests/32_/345/274/202/346/255/245/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/33_/345/220/214/346/255/245/344/270/213/345/215/225/345/233/236/350/260/203/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/34_/345/205/250/346/216/250/345/206/205/351/203/250/345/273/266/350/277/237/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/cfquant/tests/6_/345/233/236/350/260/203/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/cfquant/tests/_helpers.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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_20260921_175732.md" +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/readme.md +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_account_query_timing.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_advanced_parity.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_api_tester_browser.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_api_tester_web.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_binding_delete_confirmation.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_binding_live_refresh_browser.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_binding_runtime_browser.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_callback_recovery.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_callback_requests.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_cftrader.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_cftrader_tutorial.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_cftrader_web.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_credit_compat.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_dataframe_encoding.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_json_serialization.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_latency_flow_control.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_lite_account_routing.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_lite_deployment_paths.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_lite_parity.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_lite_qmt_dispatch.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_local_trading_calendar.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_log_management.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_management.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_management_batch.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_market_data_fallback.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_market_timing.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_order_identity.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_order_time_callback.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_project_updater.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_python_api_reference.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_qmt_binding_settings.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_qmt_dependencies.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_qmt_fileless.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_qmt_strategy_deploy.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_quote_latency.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_quote_latency_encoding.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_remote_version_check.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_setup_qmt_prompt.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_startup_recovery.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_stock_connect.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_stock_connect_browser.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_table_conversion.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_trade_strategy_callback.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_trader_subscription_recovery.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_trading_dates.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_tutorial_reader.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_tx_auto_import.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tests/test_tx_shutdown.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/trading_calendar.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tx.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/tx_trade_bridge.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/xtconstant.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/xtdata.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/xttrader.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant/xttype.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant.egg-info/dependency_links.txt +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant.egg-info/entry_points.txt +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant.egg-info/top_level.txt +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/cfquant_pipe_hub.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/qmt_scripts/CFQUANT.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/qmt_scripts/CFQUANT_CTYPE_ALL_LOWLAT.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/qmt_scripts/CFQUANT_TRADE_LOWLAT.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/qmt_scripts/__init__.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/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.56 → cfquant-0.2.57}/setup.cfg +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/__init__.py +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/api-tester.js +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/avatars/amber-pulse.svg +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/avatars/copper-grid.svg +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/avatars/market-blue.svg +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/avatars/rose-circuit.svg +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/avatars/signal-green.svg +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/avatars/slate-wave.svg +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/avatars/teal-orbit.svg +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/avatars/violet-node.svg +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/cftrader-api-data.js +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/docs.js +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/favicon.svg +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-10.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-11.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-12.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-13.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-14.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-15.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-16.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-17.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-18.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-19.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-20.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-21.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-4.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-5.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-6.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-7.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-8.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/image/qmt_deploy/image-9.png +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/python-api-data.js +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/python-api.js +0 -0
- {cfquant-0.2.56 → cfquant-0.2.57}/web_dashboard/vendor/mermaid.min.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cfquant
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.57
|
|
4
4
|
Summary: QMT local bridge and xtquant-compatible Python client.
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.8
|
|
@@ -9,6 +9,7 @@ License-File: LICENSE
|
|
|
9
9
|
Requires-Dist: pandas>=1.0
|
|
10
10
|
Requires-Dist: packaging>=20
|
|
11
11
|
Requires-Dist: psutil>=5.8
|
|
12
|
+
Requires-Dist: tomli>=1.1.0; python_version < "3.11"
|
|
12
13
|
Requires-Dist: pycryptodome>=3.20
|
|
13
14
|
Requires-Dist: pytz
|
|
14
15
|
Requires-Dist: tabulate
|
|
@@ -16,6 +16,7 @@ else:
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
PACKAGE_NAME = "cfquant"
|
|
19
|
+
TOMLI_REQUIREMENT = "tomli>=1.1.0"
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def _hidden_subprocess_kwargs():
|
|
@@ -118,6 +119,21 @@ def requirements_install_args(project_root, python_exe=None):
|
|
|
118
119
|
return command
|
|
119
120
|
|
|
120
121
|
|
|
122
|
+
def tomli_install_args(project_root=None, python_exe=None):
|
|
123
|
+
"""Build the bootstrap command needed before parsing TOML on old Python."""
|
|
124
|
+
command = [
|
|
125
|
+
python_exe or sys.executable,
|
|
126
|
+
"-m",
|
|
127
|
+
"pip",
|
|
128
|
+
"install",
|
|
129
|
+
"--disable-pip-version-check",
|
|
130
|
+
"--no-input",
|
|
131
|
+
]
|
|
132
|
+
command.extend(pip_index_args())
|
|
133
|
+
command.append(TOMLI_REQUIREMENT)
|
|
134
|
+
return command
|
|
135
|
+
|
|
136
|
+
|
|
121
137
|
def _output_tail(value, limit=6000):
|
|
122
138
|
text = str(value or "")
|
|
123
139
|
if len(text) <= int(limit):
|
|
@@ -478,7 +494,12 @@ def project_package_version(project_root):
|
|
|
478
494
|
try:
|
|
479
495
|
import tomllib
|
|
480
496
|
except ImportError:
|
|
481
|
-
|
|
497
|
+
try:
|
|
498
|
+
import tomli as tomllib
|
|
499
|
+
except ImportError:
|
|
500
|
+
# Keep compatibility with pip versions that vendor tomli while
|
|
501
|
+
# preferring the project's explicit conditional dependency.
|
|
502
|
+
from pip._vendor import tomli as tomllib
|
|
482
503
|
with (Path(project_root) / "pyproject.toml").open("rb") as stream:
|
|
483
504
|
return str(tomllib.load(stream)["project"]["version"])
|
|
484
505
|
|
|
@@ -503,7 +524,24 @@ def ensure_cfquant_installed(project_root, python_exe=None):
|
|
|
503
524
|
return 2
|
|
504
525
|
|
|
505
526
|
python_exe = python_exe or sys.executable
|
|
506
|
-
|
|
527
|
+
try:
|
|
528
|
+
expected = project_package_version(project_root)
|
|
529
|
+
except ImportError:
|
|
530
|
+
# project_package_version runs before the project itself is installed.
|
|
531
|
+
# Bootstrap tomli here so a clean Python 3.8-3.10 environment can still
|
|
532
|
+
# complete its first startup without requiring a manual pip command.
|
|
533
|
+
print("TOML parser unavailable; installing %s before startup check." % TOMLI_REQUIREMENT)
|
|
534
|
+
bootstrap = run(tomli_install_args(project_root, python_exe), project_root)
|
|
535
|
+
if bootstrap.returncode != 0:
|
|
536
|
+
print("[ERROR] Could not install %s; cannot read pyproject.toml." % TOMLI_REQUIREMENT,
|
|
537
|
+
file=sys.stderr)
|
|
538
|
+
return bootstrap.returncode
|
|
539
|
+
try:
|
|
540
|
+
expected = project_package_version(project_root)
|
|
541
|
+
except ImportError:
|
|
542
|
+
print("[ERROR] %s is still unavailable after bootstrap installation." % TOMLI_REQUIREMENT,
|
|
543
|
+
file=sys.stderr)
|
|
544
|
+
return 1
|
|
507
545
|
installed = installed_package_version(python_exe)
|
|
508
546
|
print("cfquant installed=%s project=%s" % (installed or "missing", expected))
|
|
509
547
|
if installed == expected:
|
|
@@ -100,6 +100,7 @@ class RuntimeManager:
|
|
|
100
100
|
self._process = None
|
|
101
101
|
self.accounts = AccountManager(self)
|
|
102
102
|
self.updates = UpdateManager(self)
|
|
103
|
+
self.remote = RemoteManager(self)
|
|
103
104
|
# Local service requests should never be sent to an HTTP proxy.
|
|
104
105
|
self._opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))
|
|
105
106
|
|
|
@@ -337,6 +338,21 @@ class RuntimeManager:
|
|
|
337
338
|
configure(host=info["lttx_host"], port=info["lttx_port"], transport="web_lttx")
|
|
338
339
|
|
|
339
340
|
|
|
341
|
+
class RemoteManager:
|
|
342
|
+
"""Opt-in connection using a project API key created on the official site."""
|
|
343
|
+
|
|
344
|
+
def __init__(self, runtime):
|
|
345
|
+
self.runtime = runtime
|
|
346
|
+
|
|
347
|
+
def status(self):
|
|
348
|
+
return self.runtime._request("GET", "/api/remote-management")
|
|
349
|
+
|
|
350
|
+
def configure(self, *, enabled=True, api_key=None, permissions=None):
|
|
351
|
+
body = {"enabled": bool(enabled)}
|
|
352
|
+
body.update({k: v for k, v in {"api_key": api_key, "permissions": permissions}.items() if v is not None})
|
|
353
|
+
return self.runtime._request("POST", "/api/remote-management", body)
|
|
354
|
+
|
|
355
|
+
|
|
340
356
|
class AccountManager:
|
|
341
357
|
def __init__(self, runtime):
|
|
342
358
|
self.runtime = runtime
|
|
@@ -115,10 +115,19 @@ function noticeKind(rows) {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
function submit(root) {
|
|
118
|
+
const rows = walk(root);
|
|
119
|
+
const edits = rows.filter(row => row.echo_mode === 2 && row.visible && row.enabled);
|
|
120
|
+
// Check on the GUI thread as well: an update can disable the button after
|
|
121
|
+
// Python has inspected it. A declined submission is safe to retry later.
|
|
122
|
+
if (edits.length !== 1 || !hasText(ptr(edits[0].address)) ||
|
|
123
|
+
!rows.some(row => row.visible && row.enabled && /^登\s*录(?:[((]\d+[))])?$/.test(row.label || ''))) {
|
|
124
|
+
return {submitted: false};
|
|
125
|
+
}
|
|
118
126
|
passwordEditor(root);
|
|
119
127
|
const login = fn(Process.getModuleByName('LoginDialog.dll'),
|
|
120
128
|
'?slot_loginClicked@CLoginDialog@TC@@QEAAXXZ', 'void', ['pointer']);
|
|
121
129
|
login(root);
|
|
130
|
+
return {submitted: true};
|
|
122
131
|
}
|
|
123
132
|
|
|
124
133
|
function loginIdentity(root) {
|
|
@@ -190,7 +199,7 @@ rpc.exports = {
|
|
|
190
199
|
const edits = rows.filter(row => row.echo_mode === 2 && row.visible);
|
|
191
200
|
if (edits.length > 1) throw new Error('Multiple password editors are visible');
|
|
192
201
|
return {is_login: true, has_password: edits.length === 1 && hasText(ptr(edits[0].address)),
|
|
193
|
-
busy: edits.length === 0, login_identity: loginIdentity(root), notice: noticeKind(rows),
|
|
202
|
+
busy: edits.length === 0 || !edits[0].enabled, login_identity: loginIdentity(root), notice: noticeKind(rows),
|
|
194
203
|
login_enabled: rows.some(row => row.visible && row.enabled && /^登\s*录(?:[((]\d+[))])?$/.test(row.label || ''))};
|
|
195
204
|
});
|
|
196
205
|
},
|
|
@@ -210,7 +219,7 @@ rpc.exports = {
|
|
|
210
219
|
return {acknowledged: true};
|
|
211
220
|
});
|
|
212
221
|
},
|
|
213
|
-
submit(hwnd) { return onGui(hwnd, () =>
|
|
222
|
+
submit(hwnd) { return onGui(hwnd, () => submit(getRoot(hwnd))); },
|
|
214
223
|
close(hwnd) { return onGui(hwnd, () => ({closed: closeWidget(getRoot(hwnd))})); },
|
|
215
224
|
clicklabel(hwnd, text) {
|
|
216
225
|
return onGui(hwnd, () => {
|
|
@@ -16,6 +16,10 @@ class QmtNotReady(RuntimeError):
|
|
|
16
16
|
pass
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
class QmtProcessExited(RuntimeError):
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
19
23
|
def verify_environment(directory):
|
|
20
24
|
"""Validate dependencies and native ABI before stopping a running terminal."""
|
|
21
25
|
try:
|
|
@@ -37,8 +41,13 @@ def verify_environment(directory):
|
|
|
37
41
|
raise RuntimeError("QMT 组件自动登录需要 64 位客户端")
|
|
38
42
|
|
|
39
43
|
|
|
40
|
-
def auto_login(backend, password_provider
|
|
41
|
-
|
|
44
|
+
def auto_login(backend, password_provider, *, retry_not_ready=False, login_account=None,
|
|
45
|
+
should_cancel=lambda: False, on_wait=lambda phase: None):
|
|
46
|
+
"""Wait through startup/update when managed, and submit the credential once.
|
|
47
|
+
|
|
48
|
+
Readiness retries never force a disabled button. After submission, a timeout
|
|
49
|
+
only renews observation: it is not evidence that another submission is safe.
|
|
50
|
+
"""
|
|
42
51
|
attempts = []
|
|
43
52
|
password_requested = False
|
|
44
53
|
|
|
@@ -46,28 +55,59 @@ def auto_login(backend, password_provider):
|
|
|
46
55
|
return {"outcome": outcome, "login_succeeded": outcome in ("logged_in", "already_logged_in"),
|
|
47
56
|
"attempts": attempts, "password_requested": password_requested}
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
58
|
+
while True:
|
|
59
|
+
if should_cancel():
|
|
60
|
+
return result("cancelled")
|
|
61
|
+
if backend.already_logged_in():
|
|
62
|
+
if login_account is not None:
|
|
63
|
+
backend.select_account(login_account)
|
|
64
|
+
return result("already_logged_in")
|
|
65
|
+
state = backend.state()
|
|
66
|
+
if state.get("notice") in ("challenge", "network_error"):
|
|
67
|
+
return result(state["notice"])
|
|
68
|
+
if not state.get("busy"):
|
|
69
|
+
if not password_requested or not state.get("has_password"):
|
|
70
|
+
if not password_requested:
|
|
71
|
+
if state.get("notice") == "credential_error":
|
|
72
|
+
backend.acknowledge_failure()
|
|
73
|
+
if login_account is not None:
|
|
74
|
+
backend.select_account(login_account, replace=True)
|
|
75
|
+
if should_cancel():
|
|
76
|
+
return result("cancelled")
|
|
77
|
+
password_requested = True
|
|
78
|
+
password = password_provider()
|
|
79
|
+
if not password:
|
|
80
|
+
return result("password_required")
|
|
81
|
+
try:
|
|
82
|
+
backend.fill(password)
|
|
83
|
+
finally:
|
|
84
|
+
password = None
|
|
85
|
+
state = backend.state()
|
|
86
|
+
if state.get("login_enabled") and not state.get("busy"):
|
|
87
|
+
if should_cancel():
|
|
88
|
+
return result("cancelled")
|
|
89
|
+
try:
|
|
90
|
+
backend.submit()
|
|
91
|
+
except QmtNotReady:
|
|
92
|
+
# The button can become disabled between status and submit.
|
|
93
|
+
pass
|
|
94
|
+
else:
|
|
95
|
+
attempts.append("provided")
|
|
96
|
+
break
|
|
97
|
+
if not retry_not_ready:
|
|
98
|
+
return result("login_not_ready")
|
|
99
|
+
on_wait("waiting_ready")
|
|
100
|
+
time.sleep(0.5)
|
|
101
|
+
|
|
102
|
+
on_wait("logging_in")
|
|
103
|
+
while True:
|
|
104
|
+
if should_cancel():
|
|
105
|
+
return result("cancelled")
|
|
106
|
+
outcome = backend.wait_outcome()
|
|
107
|
+
if outcome != "timeout" or not retry_not_ready:
|
|
108
|
+
return result(outcome)
|
|
109
|
+
on_wait("logging_in")
|
|
110
|
+
time.sleep(0.5)
|
|
71
111
|
|
|
72
112
|
|
|
73
113
|
def select_binding(config_path, name):
|
|
@@ -104,6 +144,7 @@ class QtLoginBackend:
|
|
|
104
144
|
self.session = None
|
|
105
145
|
self.mutex = None
|
|
106
146
|
self.messages = []
|
|
147
|
+
self.should_cancel = lambda: False
|
|
107
148
|
self.foreground_before = win32gui.GetForegroundWindow()
|
|
108
149
|
expected = (directory / "XtItClient.exe").resolve()
|
|
109
150
|
matches = []
|
|
@@ -114,6 +155,8 @@ class QtLoginBackend:
|
|
|
114
155
|
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
115
156
|
continue
|
|
116
157
|
if not matches:
|
|
158
|
+
if expected_pid is not None and not psutil.pid_exists(expected_pid):
|
|
159
|
+
raise QmtProcessExited("QMT process exited")
|
|
117
160
|
raise QmtNotReady("QMT process is not ready")
|
|
118
161
|
if len(matches) != 1:
|
|
119
162
|
raise RuntimeError("Expected exactly one running QMT for this binding directory")
|
|
@@ -167,11 +210,18 @@ class QtLoginBackend:
|
|
|
167
210
|
return result
|
|
168
211
|
|
|
169
212
|
def already_logged_in(self):
|
|
213
|
+
if self.session.is_detached:
|
|
214
|
+
raise QmtProcessExited("QMT automation session detached")
|
|
215
|
+
if not self.existing_main or self.hwnd is not None:
|
|
216
|
+
for hwnd in self.windows():
|
|
217
|
+
if self.api.status(str(hwnd))["result"].get("is_main"):
|
|
218
|
+
self.existing_main, self.main_hwnd, self.hwnd = True, hwnd, None
|
|
219
|
+
break
|
|
170
220
|
return self.existing_main and self.hwnd is None
|
|
171
221
|
|
|
172
222
|
def state(self):
|
|
173
223
|
state = self.api.status(str(self.hwnd))["result"]
|
|
174
|
-
if not state.get("is_login") or
|
|
224
|
+
if not state.get("is_login") or state.get("login_identity") != self.identity:
|
|
175
225
|
raise RuntimeError("Login window or selected account changed; stopping")
|
|
176
226
|
state.pop("login_identity", None)
|
|
177
227
|
for hwnd in self.windows():
|
|
@@ -197,8 +247,9 @@ class QtLoginBackend:
|
|
|
197
247
|
def submit(self):
|
|
198
248
|
state = self.state()
|
|
199
249
|
if not state["has_password"] or not state["login_enabled"]:
|
|
200
|
-
raise
|
|
201
|
-
self.api.submit(str(self.hwnd))
|
|
250
|
+
raise QmtNotReady("Login is not ready")
|
|
251
|
+
if not self.api.submit(str(self.hwnd))["result"]["submitted"]:
|
|
252
|
+
raise QmtNotReady("Login is not ready")
|
|
202
253
|
|
|
203
254
|
def fill(self, password):
|
|
204
255
|
self.state()
|
|
@@ -207,6 +258,10 @@ class QtLoginBackend:
|
|
|
207
258
|
def wait_outcome(self):
|
|
208
259
|
deadline = time.monotonic() + self.timeout
|
|
209
260
|
while time.monotonic() < deadline:
|
|
261
|
+
if self.should_cancel():
|
|
262
|
+
return "cancelled"
|
|
263
|
+
if self.session.is_detached:
|
|
264
|
+
raise QmtProcessExited("QMT automation session detached")
|
|
210
265
|
windows = self.windows()
|
|
211
266
|
for hwnd in windows:
|
|
212
267
|
caption = self.gui.GetWindowText(hwnd)
|
|
@@ -291,28 +346,41 @@ def main():
|
|
|
291
346
|
|
|
292
347
|
|
|
293
348
|
def login_running_qmt(directory, login_account="", password_provider=lambda: "", expected_pid=None,
|
|
294
|
-
startup_timeout=60, timeout=40
|
|
295
|
-
|
|
296
|
-
|
|
349
|
+
startup_timeout=60, timeout=40, *, should_cancel=lambda: False,
|
|
350
|
+
on_wait=lambda phase: None, before_poll=lambda: None):
|
|
351
|
+
"""Wait for QMT startup/updates and observe login until success or rejection.
|
|
352
|
+
|
|
353
|
+
The web worker uses startup_timeout=None to wait while its process is alive.
|
|
354
|
+
Cancellation stops waiting when that worker is disabled or superseded.
|
|
355
|
+
"""
|
|
356
|
+
cancelled = should_cancel
|
|
357
|
+
def should_cancel():
|
|
358
|
+
if cancelled():
|
|
359
|
+
return True
|
|
360
|
+
before_poll()
|
|
361
|
+
return cancelled()
|
|
362
|
+
|
|
363
|
+
deadline = None if startup_timeout is None else time.monotonic() + startup_timeout
|
|
364
|
+
backend = None
|
|
297
365
|
while True:
|
|
366
|
+
if should_cancel():
|
|
367
|
+
return {"outcome": "cancelled", "login_succeeded": False, "attempts": []}
|
|
298
368
|
try:
|
|
299
369
|
backend = QtLoginBackend(Path(directory), timeout, expected_pid=expected_pid)
|
|
300
370
|
break
|
|
371
|
+
except QmtProcessExited:
|
|
372
|
+
return {"outcome": "process_exited", "login_succeeded": False, "attempts": []}
|
|
301
373
|
except QmtNotReady:
|
|
302
|
-
if time.monotonic() >= deadline:
|
|
374
|
+
if deadline is not None and time.monotonic() >= deadline:
|
|
303
375
|
return {"outcome": "startup_timeout", "login_succeeded": False, "attempts": []}
|
|
376
|
+
on_wait("waiting_ready")
|
|
304
377
|
time.sleep(0.5)
|
|
305
378
|
try:
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
backend = QtLoginBackend(Path(directory), timeout, expected_pid=expected_pid)
|
|
312
|
-
elif outcome != "credential_error":
|
|
313
|
-
return {"outcome": outcome, "login_succeeded": False, "attempts": []}
|
|
314
|
-
backend.select_account(login_account, replace=True)
|
|
315
|
-
return auto_login(backend, password_provider)
|
|
379
|
+
backend.should_cancel = should_cancel
|
|
380
|
+
return auto_login(backend, password_provider, retry_not_ready=True, login_account=login_account,
|
|
381
|
+
should_cancel=should_cancel, on_wait=on_wait)
|
|
382
|
+
except QmtProcessExited:
|
|
383
|
+
return {"outcome": "process_exited", "login_succeeded": False, "attempts": []}
|
|
316
384
|
finally:
|
|
317
385
|
backend.close()
|
|
318
386
|
|