merge-cli 2.0.2__tar.gz → 3.0.0__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 (27) hide show
  1. {merge_cli-2.0.2 → merge_cli-3.0.0}/PKG-INFO +3 -4
  2. {merge_cli-2.0.2 → merge_cli-3.0.0}/merge_cli/api.py +12 -73
  3. merge_cli-3.0.0/merge_cli/cli.py +693 -0
  4. merge_cli-3.0.0/merge_cli/config.py +87 -0
  5. merge_cli-3.0.0/merge_cli/data/__init__.py +0 -0
  6. merge_cli-3.0.0/merge_cli/data/models/.gitkeep +6 -0
  7. merge_cli-3.0.0/merge_cli/data/models/BestModel_Clinvar-noncoding.pkl +0 -0
  8. merge_cli-3.0.0/merge_cli/data/models/BestModel_Clinvar.pkl +0 -0
  9. merge_cli-3.0.0/merge_cli/data/models/BestModel_Splice_Unsupervised Only.pkl +0 -0
  10. merge_cli-3.0.0/merge_cli/data/models/__init__.py +0 -0
  11. merge_cli-3.0.0/merge_cli/data/models/ensemble_predict.py +831 -0
  12. merge_cli-3.0.0/merge_cli/local_engine.py +602 -0
  13. {merge_cli-2.0.2 → merge_cli-3.0.0}/merge_cli.egg-info/PKG-INFO +3 -4
  14. {merge_cli-2.0.2 → merge_cli-3.0.0}/merge_cli.egg-info/SOURCES.txt +8 -2
  15. {merge_cli-2.0.2 → merge_cli-3.0.0}/merge_cli.egg-info/requires.txt +0 -1
  16. {merge_cli-2.0.2 → merge_cli-3.0.0}/pyproject.toml +13 -6
  17. merge_cli-2.0.2/README.md +0 -114
  18. merge_cli-2.0.2/merge_cli/cli.py +0 -754
  19. merge_cli-2.0.2/merge_cli/config.py +0 -86
  20. merge_cli-2.0.2/merge_cli/local_engine.py +0 -370
  21. {merge_cli-2.0.2 → merge_cli-3.0.0}/merge_cli/__init__.py +0 -0
  22. {merge_cli-2.0.2 → merge_cli-3.0.0}/merge_cli/ensemble_predict.py +0 -0
  23. {merge_cli-2.0.2 → merge_cli-3.0.0}/merge_cli/output.py +0 -0
  24. {merge_cli-2.0.2 → merge_cli-3.0.0}/merge_cli.egg-info/dependency_links.txt +0 -0
  25. {merge_cli-2.0.2 → merge_cli-3.0.0}/merge_cli.egg-info/entry_points.txt +0 -0
  26. {merge_cli-2.0.2 → merge_cli-3.0.0}/merge_cli.egg-info/top_level.txt +0 -0
  27. {merge_cli-2.0.2 → merge_cli-3.0.0}/setup.cfg +0 -0
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: merge-cli
3
- Version: 2.0.2
4
- Summary: MERGE 变异致病性预测 CLI(支持远程服务器和完全本地模式)
5
- Project-URL: Homepage, https://github.com/your-org/merge-cli
3
+ Version: 3.0.0
4
+ Summary: MERGE 变异致病性预测 CLI(服务器固定,集成模型内嵌,无需手动配置)
5
+ Project-URL: Homepage, https://merge.fanglab.cn
6
6
  Requires-Python: >=3.11
7
7
  Requires-Dist: click>=8.1
8
8
  Requires-Dist: rich>=13.0
9
9
  Requires-Dist: requests>=2.31
10
- Requires-Dist: keyring>=24.0
11
10
  Requires-Dist: pysam>=0.22; sys_platform != "win32"
12
11
  Requires-Dist: numpy>=1.26
13
12
  Requires-Dist: pandas>=2.1
@@ -1,44 +1,31 @@
1
1
  """
2
- merge_cli/api.py
2
+ merge_cli/api.py — v3.0.0
3
3
  封装所有对 Django 后端的 HTTP 请求。
4
- 每个函数对应 views.py 里的一个端点,参数名与 views.py 完全一致。
4
+ 服务器地址固定为 https://merge.fanglab.cn/,无需 Token 认证。
5
5
  """
6
6
  import sys
7
7
  from typing import Optional
8
8
 
9
9
  import requests
10
10
 
11
- from .config import get_api_url, get_token
11
+ from .config import FIXED_API_URL
12
12
 
13
- # 所有请求的默认超时(秒)
14
- _TIMEOUT_SINGLE = 180 # 单变异:Evo2 最慢,约 2 分钟
15
- _TIMEOUT_BATCH = 60 # 批量提交:只是上传文件,后台异步处理
13
+ _TIMEOUT_SINGLE = 180
14
+ _TIMEOUT_BATCH = 60
16
15
 
17
-
18
- def _headers() -> dict:
19
- token = get_token()
20
- h = {"Accept": "application/json"}
21
- if token:
22
- h["Authorization"] = f"Token {token}"
23
- return h
16
+ _BASE = FIXED_API_URL
24
17
 
25
18
 
26
- def _base() -> str:
27
- url = get_api_url()
28
- if not url:
29
- print("错误:未配置 API 地址。请先运行:merge config set-url https://your-server.com")
30
- sys.exit(1)
31
- return url
19
+ def _headers() -> dict:
20
+ return {"Accept": "application/json"}
32
21
 
33
22
 
34
23
  # ─────────────────────────────────────────────────────────────
35
24
  # 1. 单变异预测 POST /predict/
36
- # 对应 views.py: combined_prediction_view
37
25
  # ─────────────────────────────────────────────────────────────
38
26
  def predict_single(
39
27
  chrom: str, pos: int, ref: str, alt: str,
40
28
  genome_version: str = "hg38",
41
- # 模型开关,与 views.py POST 参数名一一对应
42
29
  use_alphagenome: bool = True,
43
30
  use_hyenadna: bool = True,
44
31
  use_nt: bool = True,
@@ -49,10 +36,6 @@ def predict_single(
49
36
  use_evo2: bool = True,
50
37
  use_evo1: bool = True,
51
38
  ) -> dict:
52
- """
53
- 调用 /predict/ 端点,返回完整 prediction 字典。
54
- 包含 dbnsfp / alphagenome / hyenadna / nt / gpn_msa / popeve / evo2 / evo1 / errors。
55
- """
56
39
  payload = {
57
40
  "chr": chrom, "pos": pos, "ref": ref, "alt": alt,
58
41
  "genome_version": genome_version,
@@ -67,7 +50,7 @@ def predict_single(
67
50
  "use_evo1": str(use_evo1).lower(),
68
51
  }
69
52
  resp = requests.post(
70
- f"{_base()}/predict/",
53
+ f"{_BASE}/predict/",
71
54
  json=payload,
72
55
  headers=_headers(),
73
56
  timeout=_TIMEOUT_SINGLE,
@@ -78,17 +61,11 @@ def predict_single(
78
61
 
79
62
  # ─────────────────────────────────────────────────────────────
80
63
  # 2. 集成模型评分 POST /ensemble/
81
- # 对应 views.py: ensemble_predict_view
82
- # 通常在 predict_single 成功后自动调用
83
64
  # ─────────────────────────────────────────────────────────────
84
65
  def predict_ensemble(prediction: dict, all_transcripts: list) -> dict:
85
- """
86
- 用 /predict/ 返回的 prediction 字典再调用 /ensemble/,
87
- 获取 MERGE 集成得分和 SHAP 图(base64 PNG)。
88
- """
89
66
  payload = {"prediction": prediction, "all_transcripts": all_transcripts}
90
67
  resp = requests.post(
91
- f"{_base()}/ensemble/",
68
+ f"{_BASE}/ensemble/",
92
69
  json=payload,
93
70
  headers=_headers(),
94
71
  timeout=_TIMEOUT_SINGLE,
@@ -99,7 +76,6 @@ def predict_ensemble(prediction: dict, all_transcripts: list) -> dict:
99
76
 
100
77
  # ─────────────────────────────────────────────────────────────
101
78
  # 3. 批量提交 POST /api/submit_batch_job/
102
- # 对应 views.py: submit_batch_job
103
79
  # ─────────────────────────────────────────────────────────────
104
80
  def submit_batch(
105
81
  vcf_path: str,
@@ -115,10 +91,6 @@ def submit_batch(
115
91
  use_evo2: bool = True,
116
92
  use_evo1: bool = True,
117
93
  ) -> dict:
118
- """
119
- 上传 VCF 文件,异步批量预测,结果发送至 email。
120
- 返回 job_id 供后续查询状态。
121
- """
122
94
  data = {
123
95
  "notify_email": email,
124
96
  "genome_version": genome_version,
@@ -134,7 +106,7 @@ def submit_batch(
134
106
  }
135
107
  with open(vcf_path, "rb") as f:
136
108
  resp = requests.post(
137
- f"{_base()}/api/submit_batch_job/",
109
+ f"{_BASE}/api/submit_batch_job/",
138
110
  data=data,
139
111
  files={"vcf_file": (vcf_path.split("/")[-1], f)},
140
112
  headers=_headers(),
@@ -146,45 +118,12 @@ def submit_batch(
146
118
 
147
119
  # ─────────────────────────────────────────────────────────────
148
120
  # 4. 查询批量任务状态 GET /api/batch_job/<job_id>/
149
- # 对应 views.py: batch_job_status
150
121
  # ─────────────────────────────────────────────────────────────
151
122
  def get_batch_status(job_id: str) -> dict:
152
123
  resp = requests.get(
153
- f"{_base()}/api/batch_job/{job_id}/",
124
+ f"{_BASE}/api/batch_job/{job_id}/",
154
125
  headers=_headers(),
155
126
  timeout=30,
156
127
  )
157
128
  resp.raise_for_status()
158
129
  return resp.json()
159
-
160
-
161
- # ─────────────────────────────────────────────────────────────
162
- # 5. 开放注册 POST /api/register/
163
- # 对应 views.py: register_and_get_token
164
- # 公开接口,不需要携带 Token
165
- # ─────────────────────────────────────────────────────────────
166
- def register(username: str, email: str, password: str) -> dict:
167
- resp = requests.post(
168
- f"{_base()}/api/register/",
169
- json={"username": username, "email": email, "password": password},
170
- headers={"Content-Type": "application/json", "Accept": "application/json"},
171
- timeout=30,
172
- )
173
- resp.raise_for_status()
174
- return resp.json()
175
-
176
-
177
- # ─────────────────────────────────────────────────────────────
178
- # 6. 已有账号重新登录取 Token POST /api/login/
179
- # 对应 views.py: login_and_get_token
180
- # 公开接口,不需要携带 Token
181
- # ─────────────────────────────────────────────────────────────
182
- def login(username: str, password: str) -> dict:
183
- resp = requests.post(
184
- f"{_base()}/api/login/",
185
- json={"username": username, "password": password},
186
- headers={"Content-Type": "application/json", "Accept": "application/json"},
187
- timeout=30,
188
- )
189
- resp.raise_for_status()
190
- return resp.json()