cnhkmcp 2.1.1__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 (117) hide show
  1. {cnhkmcp-2.1.1.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 -280
  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 -356
  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/vector_db/_manifest.json +0 -326
  22. 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/vector_db/_meta.json +0 -1
  23. 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/vector_db/be5d957c-b724-46e3-91d1-999e9f5f7d28/index_metadata.pickle +0 -0
  24. 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/vector_db/chroma.sqlite3 +0 -0
  25. 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
  26. cnhkmcp/untracked/APP/.gitignore +0 -32
  27. cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +0 -112
  28. cnhkmcp/untracked/APP/README.md +0 -309
  29. cnhkmcp/untracked/APP/Tranformer/Transformer.py +0 -4985
  30. cnhkmcp/untracked/APP/Tranformer/ace.log +0 -0
  31. cnhkmcp/untracked/APP/Tranformer/ace_lib.py +0 -1510
  32. cnhkmcp/untracked/APP/Tranformer/helpful_functions.py +0 -180
  33. cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates.json +0 -2421
  34. cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates_/321/207/320/264/342/225/221/321/204/342/225/233/320/233.json +0 -654
  35. cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_error.json +0 -1034
  36. cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_success.json +0 -444
  37. 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
  38. cnhkmcp/untracked/APP/Tranformer/parsetab.py +0 -60
  39. cnhkmcp/untracked/APP/Tranformer/template_summary.txt +0 -3182
  40. cnhkmcp/untracked/APP/Tranformer/transformer_config.json +0 -7
  41. cnhkmcp/untracked/APP/Tranformer/validator.py +0 -889
  42. cnhkmcp/untracked/APP/ace.log +0 -69
  43. cnhkmcp/untracked/APP/ace_lib.py +0 -1510
  44. cnhkmcp/untracked/APP/blueprints/__init__.py +0 -6
  45. cnhkmcp/untracked/APP/blueprints/feature_engineering.py +0 -347
  46. cnhkmcp/untracked/APP/blueprints/idea_house.py +0 -221
  47. cnhkmcp/untracked/APP/blueprints/inspiration_house.py +0 -432
  48. cnhkmcp/untracked/APP/blueprints/paper_analysis.py +0 -570
  49. cnhkmcp/untracked/APP/custom_templates/templates.json +0 -1257
  50. cnhkmcp/untracked/APP/give_me_idea/BRAIN_Alpha_Template_Expert_SystemPrompt.md +0 -400
  51. cnhkmcp/untracked/APP/give_me_idea/ace_lib.py +0 -1510
  52. cnhkmcp/untracked/APP/give_me_idea/alpha_data_specific_template_master.py +0 -252
  53. cnhkmcp/untracked/APP/give_me_idea/fetch_all_datasets.py +0 -157
  54. cnhkmcp/untracked/APP/give_me_idea/fetch_all_operators.py +0 -99
  55. cnhkmcp/untracked/APP/give_me_idea/helpful_functions.py +0 -180
  56. cnhkmcp/untracked/APP/give_me_idea/what_is_Alpha_template.md +0 -11
  57. cnhkmcp/untracked/APP/helpful_functions.py +0 -180
  58. cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +0 -1497
  59. cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +0 -447
  60. cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +0 -180
  61. cnhkmcp/untracked/APP/mirror_config.txt +0 -20
  62. cnhkmcp/untracked/APP/operaters.csv +0 -129
  63. cnhkmcp/untracked/APP/requirements.txt +0 -53
  64. cnhkmcp/untracked/APP/run_app.bat +0 -28
  65. cnhkmcp/untracked/APP/run_app.sh +0 -34
  66. cnhkmcp/untracked/APP/setup_tsinghua.bat +0 -39
  67. cnhkmcp/untracked/APP/setup_tsinghua.sh +0 -43
  68. cnhkmcp/untracked/APP/simulator/alpha_submitter.py +0 -404
  69. cnhkmcp/untracked/APP/simulator/simulator_wqb.py +0 -618
  70. cnhkmcp/untracked/APP/ssrn-3332513.pdf +6 -109201
  71. cnhkmcp/untracked/APP/static/brain.js +0 -589
  72. cnhkmcp/untracked/APP/static/decoder.js +0 -1540
  73. cnhkmcp/untracked/APP/static/feature_engineering.js +0 -1729
  74. cnhkmcp/untracked/APP/static/idea_house.js +0 -937
  75. cnhkmcp/untracked/APP/static/inspiration.js +0 -465
  76. cnhkmcp/untracked/APP/static/inspiration_house.js +0 -868
  77. cnhkmcp/untracked/APP/static/paper_analysis.js +0 -390
  78. cnhkmcp/untracked/APP/static/script.js +0 -3082
  79. cnhkmcp/untracked/APP/static/simulator.js +0 -597
  80. cnhkmcp/untracked/APP/static/styles.css +0 -3127
  81. cnhkmcp/untracked/APP/static/usage_widget.js +0 -508
  82. cnhkmcp/untracked/APP/templates/alpha_inspector.html +0 -511
  83. cnhkmcp/untracked/APP/templates/feature_engineering.html +0 -960
  84. cnhkmcp/untracked/APP/templates/idea_house.html +0 -564
  85. cnhkmcp/untracked/APP/templates/index.html +0 -932
  86. cnhkmcp/untracked/APP/templates/inspiration_house.html +0 -861
  87. cnhkmcp/untracked/APP/templates/paper_analysis.html +0 -91
  88. cnhkmcp/untracked/APP/templates/simulator.html +0 -343
  89. cnhkmcp/untracked/APP/templates/transformer_web.html +0 -580
  90. cnhkmcp/untracked/APP/usage.md +0 -351
  91. 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
  92. 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
  93. 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
  94. 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
  95. cnhkmcp/untracked/arXiv_API_Tool_Manual.md +0 -490
  96. cnhkmcp/untracked/arxiv_api.py +0 -229
  97. cnhkmcp/untracked/forum_functions.py +0 -998
  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/forum_functions.py +0 -407
  99. 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
  100. 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
  101. 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
  102. 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
  103. cnhkmcp/untracked/platform_functions.py +0 -2886
  104. cnhkmcp/untracked/sample_mcp_config.json +0 -11
  105. cnhkmcp/untracked/user_config.json +0 -31
  106. 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
  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_Alpha_explaination_workflow.md +0 -56
  108. 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
  109. 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
  110. 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
  111. 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
  112. 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
  113. cnhkmcp-2.1.1.dist-info/RECORD +0 -115
  114. cnhkmcp-2.1.1.dist-info/top_level.txt +0 -1
  115. {cnhkmcp-2.1.1.dist-info → cnhkmcp-2.1.3.dist-info}/WHEEL +0 -0
  116. {cnhkmcp-2.1.1.dist-info → cnhkmcp-2.1.3.dist-info}/entry_points.txt +0 -0
  117. {cnhkmcp-2.1.1.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()