dma-cli 0.1.1__tar.gz → 0.1.2__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 (26) hide show
  1. {dma_cli-0.1.1 → dma_cli-0.1.2}/PKG-INFO +24 -12
  2. {dma_cli-0.1.1 → dma_cli-0.1.2}/README.md +23 -11
  3. {dma_cli-0.1.1 → dma_cli-0.1.2}/config.example.yaml +1 -2
  4. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli/__init__.py +1 -1
  5. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli/client.py +11 -3
  6. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli/resources.py +6 -10
  7. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli/submit.py +3 -3
  8. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli.egg-info/PKG-INFO +24 -12
  9. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli.egg-info/SOURCES.txt +3 -1
  10. {dma_cli-0.1.1 → dma_cli-0.1.2}/pyproject.toml +1 -1
  11. dma_cli-0.1.2/tests/test_biz_platform.py +27 -0
  12. dma_cli-0.1.2/tests/test_login.py +55 -0
  13. {dma_cli-0.1.1 → dma_cli-0.1.2}/batch.example.json +0 -0
  14. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli/__main__.py +0 -0
  15. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli/calc.py +0 -0
  16. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli/cli.py +0 -0
  17. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli/state.py +0 -0
  18. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli.egg-info/dependency_links.txt +0 -0
  19. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli.egg-info/entry_points.txt +0 -0
  20. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli.egg-info/requires.txt +0 -0
  21. {dma_cli-0.1.1 → dma_cli-0.1.2}/dma_cli.egg-info/top_level.txt +0 -0
  22. {dma_cli-0.1.1 → dma_cli-0.1.2}/input/calc.py +0 -0
  23. {dma_cli-0.1.1 → dma_cli-0.1.2}/input/case1/calc.py +0 -0
  24. {dma_cli-0.1.1 → dma_cli-0.1.2}/input/case2/calc.py +0 -0
  25. {dma_cli-0.1.1 → dma_cli-0.1.2}/job.example.json +0 -0
  26. {dma_cli-0.1.1 → dma_cli-0.1.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dma-cli
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: DMA 任务提交命令行工具
5
5
  Requires-Python: >=3.8
6
6
  Description-Content-Type: text/markdown
@@ -52,12 +52,11 @@ cp config.example.yaml config.yaml
52
52
  base_url: https://szc.test.dp.tech
53
53
  auth:
54
54
  email: "" # 验证码登录邮箱(留空则必须填 token)
55
- captcha: "952754" # 验证码(测试环境)
55
+ captcha: "" # 留空,执行 dma login 时交互输入验证码
56
56
  token: "" # 直接配 token(优先于 email 登录)
57
57
  uexid: "" # 留空从 JWT 自动解析为 fe_<userId>
58
58
  user_id: "" # 留空从 JWT 自动解析
59
59
  defaults:
60
- biz_platform: 2
61
60
  name_prefix: "cli-job"
62
61
  max_run_time: 15
63
62
  max_run_time_unit: d
@@ -96,6 +95,11 @@ dma login
96
95
  dma login --email you@example.com
97
96
  ```
98
97
 
98
+ `auth.captcha` 留空时,登录会提示 `请输入邮箱验证码:`,输入本次验证码后提交。
99
+ 验证码不会保存到配置文件或登录缓存。若配置中已填写 `auth.captcha`,则使用该值;
100
+ 已有配置中的旧验证码请清空,以启用交互输入。输入为空或取消输入时,不发送登录请求。
101
+ 此命令只校验输入的验证码,不会自动发送验证码邮件。
102
+
99
103
  解析 JWT 缓存 `token` / `user_id` / `uexid` 到 `~/.dma_cli/credentials.json`。也可跳过登录,直接在 `config.yaml` 填 `token`。
100
104
 
101
105
  ### whoami —— 查看当前状态
@@ -108,12 +112,19 @@ dma whoami
108
112
 
109
113
  ### project —— 项目管理
110
114
 
115
+ 先查询当前账号可访问的项目,根据项目名称找到自己的 `projectId`,再设为当前项目:
116
+
111
117
  ```bash
112
- dma project list # 列 projectId | name
113
- dma project use 3948 # 设为当前项目
114
- dma project current # 显示当前项目
118
+ dma project list # 列出 projectId | name
119
+ dma project use <你的项目ID> # 替换为上一步查到的 projectId
120
+ dma project current # 确认当前项目 ID 和名称
115
121
  ```
116
122
 
123
+ `<你的项目ID>` 是占位符,执行前请替换为列表中你要使用的数字 ID,不要输入尖括号。
124
+ 当前项目会保存在本机,后续提交任务时省略 `--project_id` 或设置为 `0` 即使用该项目;
125
+ JSON 配置中的 `"project_id": 0` 含义相同。`0` 表示使用当前项目,不是真实项目 ID,首次提交前需先完成项目选择。
126
+ 如需单次提交到其他项目,可传入 `--project_id <你的项目ID>`,不会改变已保存的当前项目。
127
+
117
128
  ### sku —— 机型查询
118
129
 
119
130
  ```bash
@@ -146,7 +157,7 @@ dma job submit -i job.example.json
146
157
  dma job submit \
147
158
  --machine_type c2_m2_cpu \
148
159
  --image_address ubuntu:22.04-py3.10-terminal-20260916 \
149
- --project_id 3283 \
160
+ --project_id 0 \
150
161
  --command "python calc.py" \
151
162
  --job_name my-job
152
163
  ```
@@ -192,7 +203,7 @@ dma job submit \
192
203
  # {"job_name": "job-002", "machine_type": "c4_m8_cpu", ...}
193
204
  # ]
194
205
 
195
- dma job submit --batch_file batch.json --concurrency 3
206
+ dma job submit --batch_file batch.example.json --concurrency 3
196
207
  ```
197
208
 
198
209
  ### 方式三:--batch_input_dir(目录扫描)
@@ -200,7 +211,7 @@ dma job submit --batch_file batch.json --concurrency 3
200
211
  ```bash
201
212
  # 每个子目录作为一个任务的输入
202
213
  dma job submit \
203
- --batch_input_dir ./inputs \
214
+ --batch_input_dir ./input \
204
215
  --machine_type c2_m2_cpu \
205
216
  --image_address ubuntu:22.04-py3.10-terminal-20260916 \
206
217
  --command "python calc.py" \
@@ -217,9 +228,10 @@ cp config.example.yaml config.yaml
217
228
  # 2. 查看状态
218
229
  dma whoami
219
230
 
220
- # 3. 切换项目
231
+ # 3. 查询并选择自己的项目(将占位符替换为列表中的 projectId,不保留尖括号)
221
232
  dma project list
222
- dma project use 3948
233
+ dma project use <你的项目ID>
234
+ dma project current
223
235
 
224
236
  # 4. 查询机型和镜像
225
237
  dma sku list --kind cpu
@@ -229,5 +241,5 @@ dma image list
229
241
  dma job submit -i job.example.json
230
242
 
231
243
  # 6. 批量提交
232
- dma job submit --batch_file batch.json
244
+ dma job submit --batch_file batch.example.json
233
245
  ```
@@ -43,12 +43,11 @@ cp config.example.yaml config.yaml
43
43
  base_url: https://szc.test.dp.tech
44
44
  auth:
45
45
  email: "" # 验证码登录邮箱(留空则必须填 token)
46
- captcha: "952754" # 验证码(测试环境)
46
+ captcha: "" # 留空,执行 dma login 时交互输入验证码
47
47
  token: "" # 直接配 token(优先于 email 登录)
48
48
  uexid: "" # 留空从 JWT 自动解析为 fe_<userId>
49
49
  user_id: "" # 留空从 JWT 自动解析
50
50
  defaults:
51
- biz_platform: 2
52
51
  name_prefix: "cli-job"
53
52
  max_run_time: 15
54
53
  max_run_time_unit: d
@@ -87,6 +86,11 @@ dma login
87
86
  dma login --email you@example.com
88
87
  ```
89
88
 
89
+ `auth.captcha` 留空时,登录会提示 `请输入邮箱验证码:`,输入本次验证码后提交。
90
+ 验证码不会保存到配置文件或登录缓存。若配置中已填写 `auth.captcha`,则使用该值;
91
+ 已有配置中的旧验证码请清空,以启用交互输入。输入为空或取消输入时,不发送登录请求。
92
+ 此命令只校验输入的验证码,不会自动发送验证码邮件。
93
+
90
94
  解析 JWT 缓存 `token` / `user_id` / `uexid` 到 `~/.dma_cli/credentials.json`。也可跳过登录,直接在 `config.yaml` 填 `token`。
91
95
 
92
96
  ### whoami —— 查看当前状态
@@ -99,12 +103,19 @@ dma whoami
99
103
 
100
104
  ### project —— 项目管理
101
105
 
106
+ 先查询当前账号可访问的项目,根据项目名称找到自己的 `projectId`,再设为当前项目:
107
+
102
108
  ```bash
103
- dma project list # 列 projectId | name
104
- dma project use 3948 # 设为当前项目
105
- dma project current # 显示当前项目
109
+ dma project list # 列出 projectId | name
110
+ dma project use <你的项目ID> # 替换为上一步查到的 projectId
111
+ dma project current # 确认当前项目 ID 和名称
106
112
  ```
107
113
 
114
+ `<你的项目ID>` 是占位符,执行前请替换为列表中你要使用的数字 ID,不要输入尖括号。
115
+ 当前项目会保存在本机,后续提交任务时省略 `--project_id` 或设置为 `0` 即使用该项目;
116
+ JSON 配置中的 `"project_id": 0` 含义相同。`0` 表示使用当前项目,不是真实项目 ID,首次提交前需先完成项目选择。
117
+ 如需单次提交到其他项目,可传入 `--project_id <你的项目ID>`,不会改变已保存的当前项目。
118
+
108
119
  ### sku —— 机型查询
109
120
 
110
121
  ```bash
@@ -137,7 +148,7 @@ dma job submit -i job.example.json
137
148
  dma job submit \
138
149
  --machine_type c2_m2_cpu \
139
150
  --image_address ubuntu:22.04-py3.10-terminal-20260916 \
140
- --project_id 3283 \
151
+ --project_id 0 \
141
152
  --command "python calc.py" \
142
153
  --job_name my-job
143
154
  ```
@@ -183,7 +194,7 @@ dma job submit \
183
194
  # {"job_name": "job-002", "machine_type": "c4_m8_cpu", ...}
184
195
  # ]
185
196
 
186
- dma job submit --batch_file batch.json --concurrency 3
197
+ dma job submit --batch_file batch.example.json --concurrency 3
187
198
  ```
188
199
 
189
200
  ### 方式三:--batch_input_dir(目录扫描)
@@ -191,7 +202,7 @@ dma job submit --batch_file batch.json --concurrency 3
191
202
  ```bash
192
203
  # 每个子目录作为一个任务的输入
193
204
  dma job submit \
194
- --batch_input_dir ./inputs \
205
+ --batch_input_dir ./input \
195
206
  --machine_type c2_m2_cpu \
196
207
  --image_address ubuntu:22.04-py3.10-terminal-20260916 \
197
208
  --command "python calc.py" \
@@ -208,9 +219,10 @@ cp config.example.yaml config.yaml
208
219
  # 2. 查看状态
209
220
  dma whoami
210
221
 
211
- # 3. 切换项目
222
+ # 3. 查询并选择自己的项目(将占位符替换为列表中的 projectId,不保留尖括号)
212
223
  dma project list
213
- dma project use 3948
224
+ dma project use <你的项目ID>
225
+ dma project current
214
226
 
215
227
  # 4. 查询机型和镜像
216
228
  dma sku list --kind cpu
@@ -220,5 +232,5 @@ dma image list
220
232
  dma job submit -i job.example.json
221
233
 
222
234
  # 6. 批量提交
223
- dma job submit --batch_file batch.json
235
+ dma job submit --batch_file batch.example.json
224
236
  ```
@@ -4,13 +4,12 @@ base_url: https://szc.test.dp.tech
4
4
 
5
5
  auth:
6
6
  email: "" # 验证码登录邮箱(留空则必须填 token)
7
- captcha: "952754" # 固定验证码(测试环境)
7
+ captcha: "" # 留空,执行 dma login 时交互输入验证码
8
8
  token: "" # 直接配 token(优先于 email 登录,留空走 email)
9
9
  uexid: "" # 留空则从 JWT 自动解析为 fe_<userId>
10
10
  user_id: "" # 留空则从 JWT 自动解析
11
11
 
12
12
  defaults:
13
- biz_platform: 2
14
13
  name_prefix: "cli-job"
15
14
  cmd: "python calc.py"
16
15
  max_run_time: 15
@@ -1,3 +1,3 @@
1
1
  """DMA CLI —— 任务提交命令行工具"""
2
2
 
3
- __version__ = "0.1.1"
3
+ __version__ = "0.1.2"
@@ -24,11 +24,12 @@ _PKG_DIR = Path(__file__).parent
24
24
  CONFIG_FILE = Path.cwd() / "config.yaml" if (Path.cwd() / "config.yaml").exists() else _PKG_DIR / "config.yaml"
25
25
  EXAMPLE_CONFIG = _PKG_DIR / "config.example.yaml"
26
26
 
27
+ BIZ_PLATFORM = 2
28
+
27
29
  DEFAULT_CONFIG = {
28
30
  "base_url": "https://szc.test.dp.tech",
29
- "auth": {"email": "", "captcha": "952754", "token": "", "uexid": "", "user_id": ""},
31
+ "auth": {"email": "", "captcha": "", "token": "", "uexid": "", "user_id": ""},
30
32
  "defaults": {
31
- "biz_platform": 2,
32
33
  "name_prefix": "cli-job",
33
34
  "cmd": "python calc.py",
34
35
  "max_run_time": 15,
@@ -153,7 +154,14 @@ class DmaClient:
153
154
  email = email or self.config["auth"].get("email")
154
155
  if not email:
155
156
  raise RuntimeError("未配置 auth.email,无法验证码登录(请在 config.yaml 填写或改用 token)")
156
- captcha = self.config["auth"].get("captcha") or "952754"
157
+ captcha = str(self.config["auth"].get("captcha") or "").strip()
158
+ if not captcha:
159
+ try:
160
+ captcha = input("请输入邮箱验证码: ").strip()
161
+ except (EOFError, KeyboardInterrupt):
162
+ raise RuntimeError("已取消验证码输入,未发送登录请求") from None
163
+ if not captcha:
164
+ raise RuntimeError("验证码不能为空,请重新执行 dma login")
157
165
  url = self.base_url + LOGIN_PATH
158
166
  payload = {
159
167
  "channel": "gkx-talent-universe",
@@ -12,14 +12,10 @@ import sys
12
12
 
13
13
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
14
14
 
15
- from .client import STATUS_MAP
15
+ from .client import BIZ_PLATFORM, STATUS_MAP
16
16
  from .state import set_current
17
17
 
18
18
 
19
- def _biz_platform(client) -> int:
20
- return int(client.defaults.get("biz_platform", 2))
21
-
22
-
23
19
  def _print_table(headers, rows) -> None:
24
20
  """简易对齐表格打印。"""
25
21
  if not rows:
@@ -38,7 +34,7 @@ def _print_table(headers, rows) -> None:
38
34
 
39
35
  # ============ project ============
40
36
  def project_list(client) -> list:
41
- params = {"queryType": "all", "pageSize": 1000, "bizPlatform": _biz_platform(client), "page": 1}
37
+ params = {"queryType": "all", "pageSize": 1000, "bizPlatform": BIZ_PLATFORM, "page": 1}
42
38
  resp = client.get("/dmaapi/szc/v2/project/list", params=params)
43
39
  data = (resp or {}).get("data") or {}
44
40
  return data.get("items") or data.get("list") or []
@@ -123,7 +119,7 @@ def handle_sku_use(client, args) -> None:
123
119
 
124
120
  # ============ image (软件目录) ============
125
121
  def software_list(client) -> list:
126
- resp = client.get("/dmaapi/szc/v1/softwares/deep-mining", params={"bizPlatform": _biz_platform(client)})
122
+ resp = client.get("/dmaapi/szc/v1/softwares/deep-mining", params={"bizPlatform": BIZ_PLATFORM})
127
123
  return ((resp or {}).get("data") or {}).get("items") or []
128
124
 
129
125
 
@@ -155,7 +151,7 @@ def handle_image_list(client, args) -> None:
155
151
  all_images = []
156
152
 
157
153
  # 1. 查询软件目录(/softwares/deep-mining)
158
- resp = client.get("/dmaapi/szc/v1/softwares/deep-mining", params={"bizPlatform": 2})
154
+ resp = client.get("/dmaapi/szc/v1/softwares/deep-mining", params={"bizPlatform": BIZ_PLATFORM})
159
155
  if resp.get("code") == 0:
160
156
  for item in resp.get("data", {}).get("items", []):
161
157
  for version in item.get("versions", []):
@@ -170,7 +166,7 @@ def handle_image_list(client, args) -> None:
170
166
 
171
167
  # 2. 查询公共镜像(/image/public)
172
168
  resp = client.get("/dmaapi/szc/v1/image/public/deep-mining",
173
- params={"page": 1, "pageSize": 1000, "bizPlatform": 2})
169
+ params={"page": 1, "pageSize": 1000, "bizPlatform": BIZ_PLATFORM})
174
170
  if resp.get("code") == 0:
175
171
  for item in resp.get("data", {}).get("items", []):
176
172
  # url 字段可能是 img
@@ -184,7 +180,7 @@ def handle_image_list(client, args) -> None:
184
180
 
185
181
  # 3. 查询私有镜像(/image/private)
186
182
  resp = client.get("/dmaapi/szc/v1/image/private",
187
- params={"type": "image", "device": "container", "page": 1, "pageSize": 50, "bizPlatform": 2})
183
+ params={"type": "image", "device": "container", "page": 1, "pageSize": 50, "bizPlatform": BIZ_PLATFORM})
188
184
  if resp.get("code") == 0:
189
185
  for item in resp.get("data", {}).get("items", []):
190
186
  url = item.get("url") or ""
@@ -24,7 +24,7 @@ import requests
24
24
 
25
25
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
26
26
 
27
- from .client import DmaClient, STATUS_MAP
27
+ from .client import BIZ_PLATFORM, DmaClient, STATUS_MAP
28
28
 
29
29
  # 内置默认任务脚本(无 --input_directory 时上传它)
30
30
  DEFAULT_INPUT = Path(__file__).parent / "calc.py"
@@ -57,7 +57,7 @@ def find_software_by_image_address(client: DmaClient, image_address: str) -> dic
57
57
  2. softwareVersion 字段精确匹配
58
58
  3. softwareName 模糊匹配
59
59
  """
60
- resp = client.get("/dmaapi/szc/v1/softwares/deep-mining", params={"bizPlatform": 2})
60
+ resp = client.get("/dmaapi/szc/v1/softwares/deep-mining", params={"bizPlatform": BIZ_PLATFORM})
61
61
  if resp.get("code") != 0:
62
62
  raise RuntimeError(f"查询软件目录失败: code={resp.get('code')}")
63
63
 
@@ -674,4 +674,4 @@ def handle_submit(client, args):
674
674
  print("📊 轮询任务状态...")
675
675
  poll_task_status(client, result['job_id'])
676
676
  else:
677
- print(f"❌ 提交失败: {result['error']}")
677
+ print(f"❌ 提交失败: {result['error']}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dma-cli
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: DMA 任务提交命令行工具
5
5
  Requires-Python: >=3.8
6
6
  Description-Content-Type: text/markdown
@@ -52,12 +52,11 @@ cp config.example.yaml config.yaml
52
52
  base_url: https://szc.test.dp.tech
53
53
  auth:
54
54
  email: "" # 验证码登录邮箱(留空则必须填 token)
55
- captcha: "952754" # 验证码(测试环境)
55
+ captcha: "" # 留空,执行 dma login 时交互输入验证码
56
56
  token: "" # 直接配 token(优先于 email 登录)
57
57
  uexid: "" # 留空从 JWT 自动解析为 fe_<userId>
58
58
  user_id: "" # 留空从 JWT 自动解析
59
59
  defaults:
60
- biz_platform: 2
61
60
  name_prefix: "cli-job"
62
61
  max_run_time: 15
63
62
  max_run_time_unit: d
@@ -96,6 +95,11 @@ dma login
96
95
  dma login --email you@example.com
97
96
  ```
98
97
 
98
+ `auth.captcha` 留空时,登录会提示 `请输入邮箱验证码:`,输入本次验证码后提交。
99
+ 验证码不会保存到配置文件或登录缓存。若配置中已填写 `auth.captcha`,则使用该值;
100
+ 已有配置中的旧验证码请清空,以启用交互输入。输入为空或取消输入时,不发送登录请求。
101
+ 此命令只校验输入的验证码,不会自动发送验证码邮件。
102
+
99
103
  解析 JWT 缓存 `token` / `user_id` / `uexid` 到 `~/.dma_cli/credentials.json`。也可跳过登录,直接在 `config.yaml` 填 `token`。
100
104
 
101
105
  ### whoami —— 查看当前状态
@@ -108,12 +112,19 @@ dma whoami
108
112
 
109
113
  ### project —— 项目管理
110
114
 
115
+ 先查询当前账号可访问的项目,根据项目名称找到自己的 `projectId`,再设为当前项目:
116
+
111
117
  ```bash
112
- dma project list # 列 projectId | name
113
- dma project use 3948 # 设为当前项目
114
- dma project current # 显示当前项目
118
+ dma project list # 列出 projectId | name
119
+ dma project use <你的项目ID> # 替换为上一步查到的 projectId
120
+ dma project current # 确认当前项目 ID 和名称
115
121
  ```
116
122
 
123
+ `<你的项目ID>` 是占位符,执行前请替换为列表中你要使用的数字 ID,不要输入尖括号。
124
+ 当前项目会保存在本机,后续提交任务时省略 `--project_id` 或设置为 `0` 即使用该项目;
125
+ JSON 配置中的 `"project_id": 0` 含义相同。`0` 表示使用当前项目,不是真实项目 ID,首次提交前需先完成项目选择。
126
+ 如需单次提交到其他项目,可传入 `--project_id <你的项目ID>`,不会改变已保存的当前项目。
127
+
117
128
  ### sku —— 机型查询
118
129
 
119
130
  ```bash
@@ -146,7 +157,7 @@ dma job submit -i job.example.json
146
157
  dma job submit \
147
158
  --machine_type c2_m2_cpu \
148
159
  --image_address ubuntu:22.04-py3.10-terminal-20260916 \
149
- --project_id 3283 \
160
+ --project_id 0 \
150
161
  --command "python calc.py" \
151
162
  --job_name my-job
152
163
  ```
@@ -192,7 +203,7 @@ dma job submit \
192
203
  # {"job_name": "job-002", "machine_type": "c4_m8_cpu", ...}
193
204
  # ]
194
205
 
195
- dma job submit --batch_file batch.json --concurrency 3
206
+ dma job submit --batch_file batch.example.json --concurrency 3
196
207
  ```
197
208
 
198
209
  ### 方式三:--batch_input_dir(目录扫描)
@@ -200,7 +211,7 @@ dma job submit --batch_file batch.json --concurrency 3
200
211
  ```bash
201
212
  # 每个子目录作为一个任务的输入
202
213
  dma job submit \
203
- --batch_input_dir ./inputs \
214
+ --batch_input_dir ./input \
204
215
  --machine_type c2_m2_cpu \
205
216
  --image_address ubuntu:22.04-py3.10-terminal-20260916 \
206
217
  --command "python calc.py" \
@@ -217,9 +228,10 @@ cp config.example.yaml config.yaml
217
228
  # 2. 查看状态
218
229
  dma whoami
219
230
 
220
- # 3. 切换项目
231
+ # 3. 查询并选择自己的项目(将占位符替换为列表中的 projectId,不保留尖括号)
221
232
  dma project list
222
- dma project use 3948
233
+ dma project use <你的项目ID>
234
+ dma project current
223
235
 
224
236
  # 4. 查询机型和镜像
225
237
  dma sku list --kind cpu
@@ -229,5 +241,5 @@ dma image list
229
241
  dma job submit -i job.example.json
230
242
 
231
243
  # 6. 批量提交
232
- dma job submit --batch_file batch.json
244
+ dma job submit --batch_file batch.example.json
233
245
  ```
@@ -19,4 +19,6 @@ dma_cli.egg-info/requires.txt
19
19
  dma_cli.egg-info/top_level.txt
20
20
  input/calc.py
21
21
  input/case1/calc.py
22
- input/case2/calc.py
22
+ input/case2/calc.py
23
+ tests/test_biz_platform.py
24
+ tests/test_login.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dma-cli"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  description = "DMA 任务提交命令行工具"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -0,0 +1,27 @@
1
+ import unittest
2
+ from unittest.mock import Mock
3
+
4
+ from dma_cli.resources import project_list, software_list
5
+ from dma_cli.submit import find_software_by_image_address
6
+
7
+
8
+ class BizPlatformTests(unittest.TestCase):
9
+ def test_requests_ignore_legacy_platform_config(self):
10
+ for operation, args in (
11
+ (project_list, ()),
12
+ (software_list, ()),
13
+ (find_software_by_image_address, ("test-image",)),
14
+ ):
15
+ with self.subTest(operation=operation.__name__):
16
+ client = Mock()
17
+ client.defaults = {"biz_platform": 99}
18
+ client.get.return_value = {"code": 0, "data": {"items": []}}
19
+ try:
20
+ operation(client, *args)
21
+ except RuntimeError as error:
22
+ self.assertIn("未找到镜像", str(error))
23
+ self.assertEqual(client.get.call_args.kwargs["params"]["bizPlatform"], 2)
24
+
25
+
26
+ if __name__ == "__main__":
27
+ unittest.main()
@@ -0,0 +1,55 @@
1
+ import unittest
2
+ from unittest.mock import Mock, patch
3
+
4
+ from dma_cli.client import DmaClient
5
+
6
+
7
+ class LoginCaptchaTests(unittest.TestCase):
8
+ def setUp(self):
9
+ save = patch("dma_cli.client.save_creds")
10
+ save.start()
11
+ self.addCleanup(save.stop)
12
+ self.client = DmaClient.__new__(DmaClient)
13
+ self.client.config = {
14
+ "base_url": "https://example.invalid",
15
+ "auth": {"email": "user@example.invalid", "captcha": ""},
16
+ }
17
+ self.client._http = Mock()
18
+ self.client._http.post.return_value.json.return_value = {
19
+ "code": 0, "data": {"token": "test-token"}
20
+ }
21
+
22
+ def test_prompts_for_missing_captcha_and_sends_input(self):
23
+ with patch("builtins.input", return_value=" 123456 ") as prompt, \
24
+ patch("dma_cli.client.save_creds"):
25
+ self.client.login()
26
+ prompt.assert_called_once()
27
+ payload = self.client._http.post.call_args.kwargs["json"]
28
+ self.assertEqual(payload["emailCode"], "123456")
29
+ self.assertEqual(payload["code"], "123456")
30
+ self.assertEqual(self.client.config["auth"]["captcha"], "")
31
+ self.assertNotIn("captcha", self.client.creds)
32
+
33
+ def test_configured_captcha_does_not_prompt(self):
34
+ self.client.config["auth"]["captcha"] = "654321"
35
+ with patch("builtins.input") as prompt, patch("dma_cli.client.save_creds"):
36
+ self.client.login()
37
+ prompt.assert_not_called()
38
+ self.assertEqual(self.client._http.post.call_args.kwargs["json"]["code"], "654321")
39
+
40
+ def test_empty_input_does_not_send_login_request(self):
41
+ with patch("builtins.input", return_value=" "):
42
+ with self.assertRaisesRegex(RuntimeError, "验证码不能为空"):
43
+ self.client.login()
44
+ self.client._http.post.assert_not_called()
45
+
46
+ def test_cancelled_input_does_not_send_login_request(self):
47
+ for error in (EOFError, KeyboardInterrupt):
48
+ with self.subTest(error=error), patch("builtins.input", side_effect=error):
49
+ with self.assertRaisesRegex(RuntimeError, "取消验证码输入"):
50
+ self.client.login()
51
+ self.client._http.post.assert_not_called()
52
+
53
+
54
+ if __name__ == "__main__":
55
+ unittest.main()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes