cnhkmcp 1.4.5__tar.gz → 1.4.7__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.
Files changed (82) hide show
  1. {cnhkmcp-1.4.5/cnhkmcp.egg-info → cnhkmcp-1.4.7}/PKG-INFO +1 -1
  2. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/__init__.py +1 -1
  3. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/mcp/346/226/207/344/273/266/350/256/272/345/235/233/347/211/2102_/345/246/202/346/236/234/345/216/237/347/211/210/345/220/257/345/212/250/344/270/215/344/272/206/346/265/217/350/247/210/345/231/250/345/260/261/350/257/225/350/277/231/344/270/252//350/256/251AI/350/257/273/350/277/231/344/270/252/346/226/207/346/241/243/346/235/245/345/255/246/344/274/232/344/270/213/350/275/275/346/265/217/350/247/210/345/231/250.md +8 -0
  4. cnhkmcp-1.4.7/cnhkmcp/untracked/mcp/346/226/207/344/273/266/350/256/272/345/235/233/347/211/2102_/345/246/202/346/236/234/345/216/237/347/211/210/345/220/257/345/212/250/344/270/215/344/272/206/346/265/217/350/247/210/345/231/250/345/260/261/350/257/225/350/277/231/344/270/252//351/205/215/347/275/256/345/211/215/350/277/220/350/241/214/346/210/221_/345/256/211/350/243/205/345/277/205/350/246/201/344/276/235/350/265/226/345/214/205.py +190 -0
  5. cnhkmcp-1.4.7/cnhkmcp/untracked//351/205/215/347/275/256/345/211/215/350/277/220/350/241/214/346/210/221_/345/256/211/350/243/205/345/277/205/350/246/201/344/276/235/350/265/226/345/214/205.py +190 -0
  6. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7/cnhkmcp.egg-info}/PKG-INFO +1 -1
  7. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp.egg-info/SOURCES.txt +3 -1
  8. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/setup.py +1 -1
  9. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/LICENSE +0 -0
  10. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/MANIFEST.in +0 -0
  11. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/README.md +0 -0
  12. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/.gitignore +0 -0
  13. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +0 -0
  14. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/README.md +0 -0
  15. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/__pycache__/app.cpython-313.pyc +0 -0
  16. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/__init__.py +0 -0
  17. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/__pycache__/__init__.cpython-313.pyc +0 -0
  18. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/__pycache__/feature_engineering.cpython-313.pyc +0 -0
  19. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/__pycache__/idea_house.cpython-313.pyc +0 -0
  20. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/__pycache__/inspiration_house.cpython-313.pyc +0 -0
  21. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/__pycache__/paper_analysis.cpython-313.pyc +0 -0
  22. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/__pycache__/simulator.cpython-313.pyc +0 -0
  23. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/__pycache__/unified_tools.cpython-313.pyc +0 -0
  24. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/__pycache__/wqb_simulator.cpython-313.pyc +0 -0
  25. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/feature_engineering.py +0 -0
  26. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/idea_house.py +0 -0
  27. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/inspiration_house.py +0 -0
  28. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/blueprints/paper_analysis.py +0 -0
  29. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/custom_templates/templates.json +0 -0
  30. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +0 -0
  31. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +0 -0
  32. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +0 -0
  33. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/mirror_config.txt +0 -0
  34. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/operaters.csv +0 -0
  35. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/requirements.txt +0 -0
  36. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/run_app.bat +0 -0
  37. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/run_app.sh +0 -0
  38. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/setup_tsinghua.bat +0 -0
  39. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/setup_tsinghua.sh +0 -0
  40. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/simulator/__pycache__/simulator_wqb.cpython-313.pyc +0 -0
  41. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/simulator/alpha_submitter.py +0 -0
  42. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/simulator/simulator_wqb.py +0 -0
  43. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/ssrn-3332513.pdf +0 -0
  44. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/static/brain.js +0 -0
  45. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/static/decoder.js +0 -0
  46. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/static/feature_engineering.js +0 -0
  47. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/static/idea_house.js +0 -0
  48. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/static/inspiration_house.js +0 -0
  49. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/static/paper_analysis.js +0 -0
  50. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/static/script.js +0 -0
  51. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/static/simulator.js +0 -0
  52. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/static/styles.css +0 -0
  53. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/templates/feature_engineering.html +0 -0
  54. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/templates/idea_house.html +0 -0
  55. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/templates/index.html +0 -0
  56. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/templates/inspiration_house.html +0 -0
  57. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/templates/paper_analysis.html +0 -0
  58. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP/templates/simulator.html +0 -0
  59. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/APP//350/277/220/350/241/214/346/211/223/345/274/200/346/210/221.py" +0 -0
  60. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/__pycache__/forum_functions.cpython-313.pyc +0 -0
  61. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/arXiv_API_Tool_Manual.md +0 -0
  62. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/arxiv_api.py +0 -0
  63. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/forum_functions.py +0 -0
  64. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/mcp/346/226/207/344/273/266/350/256/272/345/235/233/347/211/2102_/345/246/202/346/236/234/345/216/237/347/211/210/345/220/257/345/212/250/344/270/215/344/272/206/346/265/217/350/247/210/345/231/250/345/260/261/350/257/225/350/277/231/344/270/252/forum_functions.py" +0 -0
  65. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/mcp/346/226/207/344/273/266/350/256/272/345/235/233/347/211/2102_/345/246/202/346/236/234/345/216/237/347/211/210/345/220/257/345/212/250/344/270/215/344/272/206/346/265/217/350/247/210/345/231/250/345/260/261/350/257/225/350/277/231/344/270/252/platform_functions.py" +0 -0
  66. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/mcp/346/226/207/344/273/266/350/256/272/345/235/233/347/211/2102_/345/246/202/346/236/234/345/216/237/347/211/210/345/220/257/345/212/250/344/270/215/344/272/206/346/265/217/350/247/210/345/231/250/345/260/261/350/257/225/350/277/231/344/270/252/user_config.json" +0 -0
  67. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/platform_functions.py +0 -0
  68. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/sample_mcp_config.json +0 -0
  69. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked/user_config.json +0 -0
  70. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked//347/244/272/344/276/213/345/217/202/350/200/203/346/226/207/346/241/243_BRAIN_Alpha_Test_Requirements_and_Tips.md" +0 -0
  71. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked//347/244/272/344/276/213/345/267/245/344/275/234/346/265/201_Alpha_explaination_workflow.md" +0 -0
  72. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked//347/244/272/344/276/213/345/267/245/344/275/234/346/265/201_BRAIN_6_Tips_Datafield_Exploration_Guide.md" +0 -0
  73. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked//347/244/272/344/276/213/345/267/245/344/275/234/346/265/201_BRAIN_Alpha_Improvement_Workflow.md" +0 -0
  74. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked//347/244/272/344/276/213/345/267/245/344/275/234/346/265/201_Dataset_Exploration_Expert_Manual.md" +0 -0
  75. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp/untracked//347/244/272/344/276/213/345/267/245/344/275/234/346/265/201_daily_report_workflow.md" +0 -0
  76. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp.egg-info/dependency_links.txt +0 -0
  77. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp.egg-info/entry_points.txt +0 -0
  78. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp.egg-info/not-zip-safe +0 -0
  79. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp.egg-info/requires.txt +0 -0
  80. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/cnhkmcp.egg-info/top_level.txt +0 -0
  81. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/requirements.txt +0 -0
  82. {cnhkmcp-1.4.5 → cnhkmcp-1.4.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cnhkmcp
3
- Version: 1.4.5
3
+ Version: 1.4.7
4
4
  Summary: A comprehensive Model Context Protocol (MCP) server for quantitative trading platform integration
5
5
  Home-page: https://github.com/cnhk/cnhkmcp
6
6
  Author: CNHK
@@ -50,7 +50,7 @@ from .untracked.forum_functions import (
50
50
  read_full_forum_post
51
51
  )
52
52
 
53
- __version__ = "1.4.5"
53
+ __version__ = "1.4.7"
54
54
  __author__ = "CNHK"
55
55
  __email__ = "cnhk@example.com"
56
56
 
@@ -16,6 +16,14 @@ This means Playwright cannot find the Chrome browser executable in its default s
16
16
 
17
17
  The solution is to download the Chrome `.deb` package, extract the executable, and then point your Playwright script to it.
18
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
+
19
27
  ### Step 1: Download the Chrome `.deb` Package
20
28
 
21
29
  You can download the latest stable version of Google Chrome for Debian/Ubuntu-based systems using `wget`:
@@ -0,0 +1,190 @@
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()
@@ -0,0 +1,190 @@
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()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cnhkmcp
3
- Version: 1.4.5
3
+ Version: 1.4.7
4
4
  Summary: A comprehensive Model Context Protocol (MCP) server for quantitative trading platform integration
5
5
  Home-page: https://github.com/cnhk/cnhkmcp
6
6
  Author: CNHK
@@ -23,6 +23,7 @@ cnhkmcp/untracked/示例工作流_BRAIN_6_Tips_Datafield_Exploration_Guide.md
23
23
  cnhkmcp/untracked/示例工作流_BRAIN_Alpha_Improvement_Workflow.md
24
24
  cnhkmcp/untracked/示例工作流_Dataset_Exploration_Expert_Manual.md
25
25
  cnhkmcp/untracked/示例工作流_daily_report_workflow.md
26
+ cnhkmcp/untracked/配置前运行我_安装必要依赖包.py
26
27
  cnhkmcp/untracked/APP/.gitignore
27
28
  cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md
28
29
  cnhkmcp/untracked/APP/README.md
@@ -75,4 +76,5 @@ cnhkmcp/untracked/__pycache__/forum_functions.cpython-313.pyc
75
76
  cnhkmcp/untracked/mcp文件论坛版2_如果原版启动不了浏览器就试这个/forum_functions.py
76
77
  cnhkmcp/untracked/mcp文件论坛版2_如果原版启动不了浏览器就试这个/platform_functions.py
77
78
  cnhkmcp/untracked/mcp文件论坛版2_如果原版启动不了浏览器就试这个/user_config.json
78
- cnhkmcp/untracked/mcp文件论坛版2_如果原版启动不了浏览器就试这个/让AI读这个文档来学会下载浏览器.md
79
+ cnhkmcp/untracked/mcp文件论坛版2_如果原版启动不了浏览器就试这个/让AI读这个文档来学会下载浏览器.md
80
+ cnhkmcp/untracked/mcp文件论坛版2_如果原版启动不了浏览器就试这个/配置前运行我_安装必要依赖包.py
@@ -13,7 +13,7 @@ def read_requirements():
13
13
 
14
14
  setup(
15
15
  name="cnhkmcp",
16
- version="1.4.5",
16
+ version="1.4.7",
17
17
  author="CNHK",
18
18
  author_email="cnhk@example.com",
19
19
  description="A comprehensive Model Context Protocol (MCP) server for quantitative trading platform integration",
File without changes
File without changes
File without changes
File without changes
File without changes