cnhkmcp 2.1.2__py3-none-any.whl → 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.
Files changed (113) hide show
  1. {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/METADATA +1 -1
  2. cnhkmcp-2.1.3.dist-info/RECORD +6 -0
  3. cnhkmcp-2.1.3.dist-info/top_level.txt +1 -0
  4. cnhkmcp/__init__.py +0 -125
  5. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/README.md +0 -38
  6. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/ace.log +0 -0
  7. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/config.json +0 -6
  8. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/ace_lib.py +0 -1510
  9. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_datasets.py +0 -157
  10. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_documentation.py +0 -132
  11. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_operators.py +0 -99
  12. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/helpful_functions.py +0 -180
  13. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/icon.ico +0 -0
  14. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/icon.png +0 -0
  15. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/test.txt +0 -1
  16. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/main.py +0 -576
  17. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/process_knowledge_base.py +0 -281
  18. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/rag_engine.py +0 -408
  19. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/requirements.txt +0 -7
  20. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/run.bat +0 -3
  21. cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242//321/211/320/266/320/246/321/206/320/274/320/261/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +0 -265
  22. cnhkmcp/untracked/APP/.gitignore +0 -32
  23. cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +0 -112
  24. cnhkmcp/untracked/APP/README.md +0 -309
  25. cnhkmcp/untracked/APP/Tranformer/Transformer.py +0 -4985
  26. cnhkmcp/untracked/APP/Tranformer/ace.log +0 -0
  27. cnhkmcp/untracked/APP/Tranformer/ace_lib.py +0 -1510
  28. cnhkmcp/untracked/APP/Tranformer/helpful_functions.py +0 -180
  29. cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates.json +0 -2421
  30. cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates_/321/207/320/264/342/225/221/321/204/342/225/233/320/233.json +0 -654
  31. cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_error.json +0 -1034
  32. cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_success.json +0 -444
  33. cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_/321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/320/237/320/277/321/207/320/253/342/224/244/321/206/320/236/320/265/321/210/342/225/234/342/225/234/321/205/320/225/320/265Machine_lib.json +0 -22
  34. cnhkmcp/untracked/APP/Tranformer/parsetab.py +0 -60
  35. cnhkmcp/untracked/APP/Tranformer/template_summary.txt +0 -3182
  36. cnhkmcp/untracked/APP/Tranformer/transformer_config.json +0 -7
  37. cnhkmcp/untracked/APP/Tranformer/validator.py +0 -889
  38. cnhkmcp/untracked/APP/ace.log +0 -69
  39. cnhkmcp/untracked/APP/ace_lib.py +0 -1510
  40. cnhkmcp/untracked/APP/blueprints/__init__.py +0 -6
  41. cnhkmcp/untracked/APP/blueprints/feature_engineering.py +0 -347
  42. cnhkmcp/untracked/APP/blueprints/idea_house.py +0 -221
  43. cnhkmcp/untracked/APP/blueprints/inspiration_house.py +0 -432
  44. cnhkmcp/untracked/APP/blueprints/paper_analysis.py +0 -570
  45. cnhkmcp/untracked/APP/custom_templates/templates.json +0 -1257
  46. cnhkmcp/untracked/APP/give_me_idea/BRAIN_Alpha_Template_Expert_SystemPrompt.md +0 -400
  47. cnhkmcp/untracked/APP/give_me_idea/ace_lib.py +0 -1510
  48. cnhkmcp/untracked/APP/give_me_idea/alpha_data_specific_template_master.py +0 -252
  49. cnhkmcp/untracked/APP/give_me_idea/fetch_all_datasets.py +0 -157
  50. cnhkmcp/untracked/APP/give_me_idea/fetch_all_operators.py +0 -99
  51. cnhkmcp/untracked/APP/give_me_idea/helpful_functions.py +0 -180
  52. cnhkmcp/untracked/APP/give_me_idea/what_is_Alpha_template.md +0 -11
  53. cnhkmcp/untracked/APP/helpful_functions.py +0 -180
  54. cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +0 -1497
  55. cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +0 -447
  56. cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +0 -180
  57. cnhkmcp/untracked/APP/mirror_config.txt +0 -20
  58. cnhkmcp/untracked/APP/operaters.csv +0 -129
  59. cnhkmcp/untracked/APP/requirements.txt +0 -53
  60. cnhkmcp/untracked/APP/run_app.bat +0 -28
  61. cnhkmcp/untracked/APP/run_app.sh +0 -34
  62. cnhkmcp/untracked/APP/setup_tsinghua.bat +0 -39
  63. cnhkmcp/untracked/APP/setup_tsinghua.sh +0 -43
  64. cnhkmcp/untracked/APP/simulator/alpha_submitter.py +0 -404
  65. cnhkmcp/untracked/APP/simulator/simulator_wqb.py +0 -618
  66. cnhkmcp/untracked/APP/ssrn-3332513.pdf +6 -109201
  67. cnhkmcp/untracked/APP/static/brain.js +0 -589
  68. cnhkmcp/untracked/APP/static/decoder.js +0 -1540
  69. cnhkmcp/untracked/APP/static/feature_engineering.js +0 -1729
  70. cnhkmcp/untracked/APP/static/idea_house.js +0 -937
  71. cnhkmcp/untracked/APP/static/inspiration.js +0 -465
  72. cnhkmcp/untracked/APP/static/inspiration_house.js +0 -868
  73. cnhkmcp/untracked/APP/static/paper_analysis.js +0 -390
  74. cnhkmcp/untracked/APP/static/script.js +0 -3082
  75. cnhkmcp/untracked/APP/static/simulator.js +0 -597
  76. cnhkmcp/untracked/APP/static/styles.css +0 -3127
  77. cnhkmcp/untracked/APP/static/usage_widget.js +0 -508
  78. cnhkmcp/untracked/APP/templates/alpha_inspector.html +0 -511
  79. cnhkmcp/untracked/APP/templates/feature_engineering.html +0 -960
  80. cnhkmcp/untracked/APP/templates/idea_house.html +0 -564
  81. cnhkmcp/untracked/APP/templates/index.html +0 -932
  82. cnhkmcp/untracked/APP/templates/inspiration_house.html +0 -861
  83. cnhkmcp/untracked/APP/templates/paper_analysis.html +0 -91
  84. cnhkmcp/untracked/APP/templates/simulator.html +0 -343
  85. cnhkmcp/untracked/APP/templates/transformer_web.html +0 -580
  86. cnhkmcp/untracked/APP/usage.md +0 -351
  87. cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/ace_lib.py +0 -1510
  88. cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/brain_alpha_inspector.py +0 -712
  89. cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/helpful_functions.py +0 -180
  90. cnhkmcp/untracked/APP//321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +0 -2456
  91. cnhkmcp/untracked/arXiv_API_Tool_Manual.md +0 -490
  92. cnhkmcp/untracked/arxiv_api.py +0 -229
  93. cnhkmcp/untracked/forum_functions.py +0 -998
  94. cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/forum_functions.py +0 -407
  95. cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/platform_functions.py +0 -2415
  96. cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/user_config.json +0 -31
  97. cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272//321/210/320/276/320/271AI/321/210/320/277/342/225/227/321/210/342/224/220/320/251/321/204/342/225/225/320/272/321/206/320/246/320/227/321/206/320/261/320/263/321/206/320/255/320/265/321/205/320/275/320/266/321/204/342/225/235/320/252/321/204/342/225/225/320/233/321/210/342/225/234/342/225/234/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270.md +0 -101
  98. cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272//321/211/320/225/320/235/321/207/342/225/234/320/276/321/205/320/231/320/235/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/230/320/241_/321/205/320/276/320/231/321/210/320/263/320/225/321/205/342/224/220/320/225/321/210/320/266/320/221/321/204/342/225/233/320/255/321/210/342/225/241/320/246/321/205/320/234/320/225.py +0 -190
  99. cnhkmcp/untracked/platform_functions.py +0 -2886
  100. cnhkmcp/untracked/sample_mcp_config.json +0 -11
  101. cnhkmcp/untracked/user_config.json +0 -31
  102. cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/320/237/320/222/321/210/320/220/320/223/321/206/320/246/320/227/321/206/320/261/320/263_BRAIN_Alpha_Test_Requirements_and_Tips.md +0 -202
  103. cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_Alpha_explaination_workflow.md +0 -56
  104. cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_BRAIN_6_Tips_Datafield_Exploration_Guide.md +0 -194
  105. cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_BRAIN_Alpha_Improvement_Workflow.md +0 -101
  106. cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_Dataset_Exploration_Expert_Manual.md +0 -436
  107. cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_daily_report_workflow.md +0 -128
  108. cnhkmcp/untracked//321/211/320/225/320/235/321/207/342/225/234/320/276/321/205/320/231/320/235/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/230/320/241_/321/205/320/276/320/231/321/210/320/263/320/225/321/205/342/224/220/320/225/321/210/320/266/320/221/321/204/342/225/233/320/255/321/210/342/225/241/320/246/321/205/320/234/320/225.py +0 -190
  109. cnhkmcp-2.1.2.dist-info/RECORD +0 -111
  110. cnhkmcp-2.1.2.dist-info/top_level.txt +0 -1
  111. {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/WHEEL +0 -0
  112. {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/entry_points.txt +0 -0
  113. {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,31 +0,0 @@
1
- {
2
- "credentials": {
3
- "email": "youremail@mai.com",
4
- "password": "yourpassword"
5
- },
6
- "api_settings": {
7
- "base_url": "https://api.worldquantbrain.com",
8
- "timeout": 30,
9
- "retry_attempts": 3
10
- },
11
- "forum_settings": {
12
- "base_url": "https://support.worldquantbrain.com",
13
- "headless": true,
14
- "timeout": 30
15
- },
16
- "simulation_defaults": {
17
- "type": "REGULAR",
18
- "instrument_type": "EQUITY",
19
- "region": "USA",
20
- "universe": "TOP3000",
21
- "delay": 1,
22
- "decay": 0,
23
- "neutralization": "NONE",
24
- "truncation": 0,
25
- "test_period": "P0Y0M",
26
- "unit_handling": "NONE",
27
- "nan_handling": "NONE",
28
- "language": "FASTEXPR",
29
- "visualization": true
30
- }
31
- }
@@ -1,101 +0,0 @@
1
- # Guide: Setting Up Playwright with a Local Chrome Executable
2
-
3
- This guide explains how to configure Playwright to use a locally extracted Google Chrome browser. This is useful in environments where you don't have `sudo` permissions to install Chrome or its dependencies system-wide.
4
-
5
- ## The Problem
6
-
7
- When running a Playwright script, you might encounter an error like this:
8
-
9
- ```
10
- playwright._impl._errors.Error: BrowserType.launch: Executable doesn't exist at ...
11
- ```
12
-
13
- This means Playwright cannot find the Chrome browser executable in its default search paths.
14
-
15
- ## The Solution: Local Extraction
16
-
17
- The solution is to download the Chrome `.deb` package, extract the executable, and then point your Playwright script to it.
18
-
19
- ### Step 0: pip install playwright
20
-
21
- Before you begin, make sure you have Playwright installed. You can install it using pip:
22
-
23
- ```bash
24
- pip install playwright
25
- ```
26
-
27
- ### Step 1: Download the Chrome `.deb` Package
28
-
29
- You can download the latest stable version of Google Chrome for Debian/Ubuntu-based systems using `wget`:
30
-
31
- ```bash
32
- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
33
- ```
34
-
35
- ### Step 2: Extract the Executable
36
-
37
- Once you have the `.deb` file, you can extract its contents without installing it.
38
-
39
- 1. **Extract the `.deb` archive:** The `ar` command extracts the contents of the `.deb` file.
40
-
41
- ```bash
42
- ar x google-chrome-stable_current_amd64.deb
43
- ```
44
-
45
- This will create several files, including `data.tar.xz`.
46
-
47
- 2. **Extract the data archive:** The `data.tar.xz` file contains the actual program files.
48
-
49
- ```bash
50
- tar -xf data.tar.xz
51
- ```
52
-
53
- This will create an `opt` directory in your current location.
54
-
55
- ### Step 3: Locate the Chrome Executable
56
-
57
- The Chrome executable is now located at `./opt/google/chrome/chrome`.
58
-
59
- ### Step 4: Configure Your Playwright Script
60
-
61
- In your Python script forum_functions.py, you need to tell Playwright where to find the Chrome executable by using the `executable_path` argument when launching the browser.
62
-
63
- It is best practice to use an **absolute path** to avoid issues with the script's working directory. You can construct the absolute path by combining your project's root directory with the relative path to the executable.
64
-
65
- Here is an example:
66
-
67
- ```python
68
- import os
69
- from playwright.async_api import async_playwright
70
- import asyncio
71
-
72
- async def main():
73
- # Get the absolute path to the executable
74
- project_dir = os.getcwd() # Or specify your project's absolute path
75
- executable_path = os.path.join(project_dir, 'opt/google/chrome/chrome')
76
-
77
- async with async_playwright() as p:
78
- browser = await p.chromium.launch(
79
- executable_path=executable_path,
80
- args=['--headless=new', '--no-sandbox']
81
- )
82
- page = await browser.new_page()
83
- await page.goto('http://playwright.dev')
84
- print(await page.title())
85
- await browser.close()
86
-
87
- if __name__ == '__main__':
88
- asyncio.run(main())
89
- ```
90
-
91
- By providing the absolute `executable_path`, you are explicitly telling Playwright where to find the browser, making your script more robust.
92
-
93
- ## Alternative: `playwright install`
94
-
95
- If you have `sudo` permissions, the recommended way to install the browsers for Playwright is to use the following command:
96
-
97
- ```bash
98
- playwright install --with-deps
99
- ```
100
-
101
- This will download the browser and also install all the necessary system dependencies.
@@ -1,190 +0,0 @@
1
- """
2
- check_install_packages.py
3
-
4
- Simple script that hardcodes the project's required packages and ensures they are installed
5
- before running the server or tests. It will install missing packages (or upgrade if below
6
- required version) by invoking pip via the running Python interpreter.
7
-
8
- Usage: python check_install_packages.py
9
-
10
- This script is intentionally conservative: it uses the distribution/package names from
11
- `requirements.txt` and calls pip to install the exact spec (e.g. "requests>=2.31.0").
12
- It prints a concise summary at the end.
13
- """
14
-
15
- from __future__ import annotations
16
- import sys
17
- import subprocess
18
- import importlib
19
- import importlib.metadata
20
- import re
21
- from typing import List, Tuple, Optional
22
-
23
- # Hardcoded package requirements (from requirements.txt)
24
- REQUIRED_PACKAGES: List[str] = [
25
- "fastmcp>=0.1.0",
26
- "requests>=2.31.0",
27
- "pandas>=2.0.0",
28
- "selenium>=4.15.0",
29
- "beautifulsoup4>=4.12.0",
30
- "pydantic>=2.0.0",
31
- "email-validator>=2.0.0",
32
- "aiohttp>=3.8.0",
33
- "webdriver-manager>=4.0.0"
34
- ]
35
-
36
-
37
- def parse_spec(spec: str) -> Tuple[str, Optional[str]]:
38
- """Return (name, min_version) for a spec like 'pkg>=1.2.3'."""
39
- if ">=" in spec:
40
- name, ver = spec.split(">=", 1)
41
- return name.strip(), ver.strip()
42
- return spec.strip(), None
43
-
44
-
45
- def version_tuple(v: str) -> List[int]:
46
- parts = re.split(r"[^0-9]+", v)
47
- nums = []
48
- for p in parts:
49
- if p == "":
50
- continue
51
- try:
52
- nums.append(int(p))
53
- except ValueError:
54
- # Non-numeric part, stop parsing further
55
- break
56
- return nums
57
-
58
-
59
- def is_version_sufficient(installed: str, required: str) -> bool:
60
- if not installed:
61
- return False
62
- try:
63
- i_parts = version_tuple(installed)
64
- r_parts = version_tuple(required)
65
- # Compare element-wise
66
- for a, b in zip(i_parts, r_parts):
67
- if a > b:
68
- return True
69
- if a < b:
70
- return False
71
- # If equal up to the length of required, installed is sufficient if it's at least as long
72
- return len(i_parts) >= len(r_parts)
73
- except Exception:
74
- return False
75
-
76
-
77
- def install_package(spec: str) -> Tuple[bool, str]:
78
- """Install a package spec using pip. Streams output live and returns (success, output)."""
79
- # Use -v for verbose pip output; capture stdout/stderr while streaming to console
80
- cmd = [sys.executable, "-m", "pip", "install", "-v", spec]
81
- try:
82
- proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
83
- output_lines = []
84
- if proc.stdout:
85
- for line in proc.stdout:
86
- output_lines.append(line)
87
- # print each pip line as it arrives for visibility
88
- try:
89
- print(line.rstrip())
90
- except Exception:
91
- # fallback: print raw line
92
- print(line)
93
- proc.wait()
94
- out = "".join(output_lines)
95
- success = proc.returncode == 0
96
- return success, out
97
- except Exception as e:
98
- return False, str(e)
99
-
100
-
101
- def main():
102
- results = []
103
- print("Checking required packages...\n")
104
- for spec in REQUIRED_PACKAGES:
105
- name, min_ver = parse_spec(spec)
106
- installed_ver = None
107
- try:
108
- installed_ver = importlib.metadata.version(name)
109
- except importlib.metadata.PackageNotFoundError:
110
- installed_ver = None
111
- except Exception:
112
- # Some packages may have different distribution vs import names; try best-effort
113
- installed_ver = None
114
-
115
- needs_install = False
116
- action = "present"
117
- if installed_ver is None:
118
- needs_install = True
119
- action = "install"
120
- elif min_ver is not None:
121
- if not is_version_sufficient(installed_ver, min_ver):
122
- needs_install = True
123
- action = f"upgrade (installed {installed_ver} < required {min_ver})"
124
-
125
- if needs_install:
126
- print(f"-> {name}: {action} via pip ({spec})")
127
- success, output = install_package(spec)
128
- # Attempt to read installed version after install
129
- installed_after = None
130
- if success:
131
- try:
132
- installed_after = importlib.metadata.version(name)
133
- except Exception:
134
- installed_after = None
135
- if installed_after:
136
- print(f" -> {name} now installed as: {installed_after}")
137
-
138
- results.append({
139
- "name": name,
140
- "spec": spec,
141
- "installed_version_before": installed_ver,
142
- "installed_version_after": installed_after,
143
- "action": action,
144
- "success": success,
145
- "output": output
146
- })
147
- else:
148
- print(f"-> {name}: OK (installed: {installed_ver})")
149
- results.append({
150
- "name": name,
151
- "spec": spec,
152
- "installed_version_before": installed_ver,
153
- "action": "none",
154
- "success": True,
155
- "output": ""
156
- })
157
-
158
- # Summary
159
- print("\nSummary:")
160
- installed_count = sum(1 for r in results if r["success"] and r["action"] == "none")
161
- installed_or_fixed = sum(1 for r in results if r["success"] and r["action"] != "none")
162
- failed = [r for r in results if not r["success"]]
163
-
164
- print(f" Packages already OK: {installed_count}")
165
- print(f" Packages installed/upgraded by this script: {installed_or_fixed}")
166
- print(f" Packages failed to install: {len(failed)}")
167
- if failed:
168
- for f in failed:
169
- print(f" - {f['name']}: attempted '{f['spec']}' -> error (see details below)")
170
-
171
- # If any failed, print their outputs for debugging
172
- if failed:
173
- print("\nFailed install details:\n")
174
- for f in failed:
175
- print("-----")
176
- print(f"Package: {f['name']}")
177
- print(f"Spec: {f['spec']}")
178
- print(f"Installed before: {f.get('installed_version_before')}")
179
- print(f"Installed after: {f.get('installed_version_after')}")
180
- print("Output:")
181
- print(f.get("output", "(no output)"))
182
-
183
- print("\nDone.")
184
- # Exit with non-zero code if any install failed
185
- if failed:
186
- sys.exit(2)
187
-
188
-
189
- if __name__ == "__main__":
190
- main()