amap-cli 0.1.3__tar.gz → 0.1.4__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 (25) hide show
  1. amap_cli-0.1.3/README.md → amap_cli-0.1.4/PKG-INFO +32 -0
  2. amap_cli-0.1.3/PKG-INFO → amap_cli-0.1.4/README.md +25 -7
  3. {amap_cli-0.1.3 → amap_cli-0.1.4}/docs/manual-verification.md +2 -0
  4. {amap_cli-0.1.3 → amap_cli-0.1.4}/pyproject.toml +1 -1
  5. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/api.py +29 -24
  6. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/cli.py +8 -1
  7. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/config.py +18 -0
  8. {amap_cli-0.1.3 → amap_cli-0.1.4}/uv.lock +1 -1
  9. {amap_cli-0.1.3 → amap_cli-0.1.4}/.gitignore +0 -0
  10. {amap_cli-0.1.3 → amap_cli-0.1.4}/.trae/specs/build-amap-cli/checklist.md +0 -0
  11. {amap_cli-0.1.3 → amap_cli-0.1.4}/.trae/specs/build-amap-cli/spec.md +0 -0
  12. {amap_cli-0.1.3 → amap_cli-0.1.4}/.trae/specs/build-amap-cli/tasks.md +0 -0
  13. {amap_cli-0.1.3 → amap_cli-0.1.4}/amap-gui-reference.md +0 -0
  14. {amap_cli-0.1.3 → amap_cli-0.1.4}/skills/amap-cli/SKILL.md +0 -0
  15. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/__init__.py +0 -0
  16. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/__main__.py +0 -0
  17. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/distance.py +0 -0
  18. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/errors.py +0 -0
  19. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/geocode.py +0 -0
  20. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/geocode_command.py +0 -0
  21. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/output.py +0 -0
  22. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/params.py +0 -0
  23. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/route.py +0 -0
  24. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/search_poi.py +0 -0
  25. {amap_cli-0.1.3 → amap_cli-0.1.4}/src/amap_cli/skill.py +0 -0
@@ -1,3 +1,10 @@
1
+ Metadata-Version: 2.5
2
+ Name: amap-cli
3
+ Version: 0.1.4
4
+ Summary: Pure command-line CLI for Amap APIs.
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+
1
8
  # amap-cli
2
9
 
3
10
  `amap-cli` 是一个基于高德开放平台 Web API 的纯命令行工具,面向终端环境和 AI Agent 使用。
@@ -29,6 +36,13 @@ uvx amap-cli --help
29
36
  uvx amap-cli config set --api-key <YOUR_AMAP_KEY>
30
37
  ```
31
38
 
39
+ 高德免费账号默认限流较严,工具默认会在每次 API 调用结束后 sleep `0.34` 秒;如需调整或关闭,可配置:
40
+
41
+ ```bash
42
+ uvx amap-cli config set --request-sleep-seconds 0.34
43
+ uvx amap-cli config set --request-sleep-seconds 0
44
+ ```
45
+
32
46
  地理编码示例:
33
47
 
34
48
  ```bash
@@ -123,6 +137,18 @@ amap-cli install-skill --dir ~/.agents/skills --force
123
137
  amap-cli config set --api-key <YOUR_AMAP_KEY>
124
138
  ```
125
139
 
140
+ 设置每次高德 API 调用结束后的 sleep 时间:
141
+
142
+ ```bash
143
+ amap-cli config set --request-sleep-seconds 0.34
144
+ ```
145
+
146
+ 关闭该 sleep:
147
+
148
+ ```bash
149
+ amap-cli config set --request-sleep-seconds 0
150
+ ```
151
+
126
152
  查看当前配置:
127
153
 
128
154
  ```bash
@@ -135,6 +161,12 @@ amap-cli config show
135
161
  ~/Library/Application Support/amap-cli/config.json
136
162
  ```
137
163
 
164
+ 说明:
165
+
166
+ - `request_sleep_seconds` 默认为 `0.34`
167
+ - 该配置会在每次真实的高德 API 调用结束后执行一次 sleep
168
+ - 设置为 `0` 表示关闭节流等待
169
+
138
170
  ### 安装 Skill
139
171
 
140
172
  基础格式:
@@ -1,10 +1,3 @@
1
- Metadata-Version: 2.5
2
- Name: amap-cli
3
- Version: 0.1.3
4
- Summary: Pure command-line CLI for Amap APIs.
5
- Requires-Python: >=3.11
6
- Description-Content-Type: text/markdown
7
-
8
1
  # amap-cli
9
2
 
10
3
  `amap-cli` 是一个基于高德开放平台 Web API 的纯命令行工具,面向终端环境和 AI Agent 使用。
@@ -36,6 +29,13 @@ uvx amap-cli --help
36
29
  uvx amap-cli config set --api-key <YOUR_AMAP_KEY>
37
30
  ```
38
31
 
32
+ 高德免费账号默认限流较严,工具默认会在每次 API 调用结束后 sleep `0.34` 秒;如需调整或关闭,可配置:
33
+
34
+ ```bash
35
+ uvx amap-cli config set --request-sleep-seconds 0.34
36
+ uvx amap-cli config set --request-sleep-seconds 0
37
+ ```
38
+
39
39
  地理编码示例:
40
40
 
41
41
  ```bash
@@ -130,6 +130,18 @@ amap-cli install-skill --dir ~/.agents/skills --force
130
130
  amap-cli config set --api-key <YOUR_AMAP_KEY>
131
131
  ```
132
132
 
133
+ 设置每次高德 API 调用结束后的 sleep 时间:
134
+
135
+ ```bash
136
+ amap-cli config set --request-sleep-seconds 0.34
137
+ ```
138
+
139
+ 关闭该 sleep:
140
+
141
+ ```bash
142
+ amap-cli config set --request-sleep-seconds 0
143
+ ```
144
+
133
145
  查看当前配置:
134
146
 
135
147
  ```bash
@@ -142,6 +154,12 @@ amap-cli config show
142
154
  ~/Library/Application Support/amap-cli/config.json
143
155
  ```
144
156
 
157
+ 说明:
158
+
159
+ - `request_sleep_seconds` 默认为 `0.34`
160
+ - 该配置会在每次真实的高德 API 调用结束后执行一次 sleep
161
+ - 设置为 `0` 表示关闭节流等待
162
+
145
163
  ### 安装 Skill
146
164
 
147
165
  基础格式:
@@ -74,6 +74,7 @@ uv run amap-cli distance --from 116.397,39.909 --to 116.407,39.904
74
74
  ```bash
75
75
  TMP_HOME=$(mktemp -d)
76
76
  HOME="$TMP_HOME" uv run amap-cli config set --api-key test-demo-key --timeout-seconds 12
77
+ HOME="$TMP_HOME" uv run amap-cli config set --request-sleep-seconds 0
77
78
  HOME="$TMP_HOME" uv run amap-cli config show
78
79
  ```
79
80
 
@@ -83,6 +84,7 @@ HOME="$TMP_HOME" uv run amap-cli config show
83
84
  - macOS 下配置落在 `~/Library/Application Support/amap-cli/config.json`
84
85
  - 再次执行 `config show` 时可自动读取刚写入的配置
85
86
  - `api_key` 输出已脱敏
87
+ - `request_sleep_seconds` 可写入为 `0`,用于关闭默认的请求后 sleep
86
88
 
87
89
  ### 5. `route` 典型输入通过 CLI 主入口走通到 handler
88
90
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "amap-cli"
7
- version = "0.1.3"
7
+ version = "0.1.4"
8
8
  description = "Pure command-line CLI for Amap APIs."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import json
6
+ import time
6
7
  from typing import Any
7
8
  from urllib.error import HTTPError, URLError
8
9
  from urllib.parse import urlencode
@@ -39,32 +40,36 @@ class AmapApiClient:
39
40
  )
40
41
 
41
42
  try:
42
- with urlopen(request, timeout=self.config.timeout_seconds) as response:
43
- body = response.read().decode("utf-8")
44
- except HTTPError as exc:
45
- response_body = exc.read().decode("utf-8", errors="ignore")
46
- raise ApiRequestError(
47
- f"高德 API HTTP 请求失败:{exc.code}",
48
- details={"status": exc.code, "body": response_body},
49
- ) from exc
50
- except URLError as exc:
51
- raise ApiRequestError(
52
- "无法连接高德 API。",
53
- details={"reason": str(exc.reason)},
54
- ) from exc
55
- except TimeoutError as exc:
56
- raise ApiRequestError("请求高德 API 超时。") from exc
43
+ try:
44
+ with urlopen(request, timeout=self.config.timeout_seconds) as response:
45
+ body = response.read().decode("utf-8")
46
+ except HTTPError as exc:
47
+ response_body = exc.read().decode("utf-8", errors="ignore")
48
+ raise ApiRequestError(
49
+ f"高德 API HTTP 请求失败:{exc.code}",
50
+ details={"status": exc.code, "body": response_body},
51
+ ) from exc
52
+ except URLError as exc:
53
+ raise ApiRequestError(
54
+ "无法连接高德 API。",
55
+ details={"reason": str(exc.reason)},
56
+ ) from exc
57
+ except TimeoutError as exc:
58
+ raise ApiRequestError("请求高德 API 超时。") from exc
57
59
 
58
- try:
59
- payload = json.loads(body)
60
- except json.JSONDecodeError as exc:
61
- raise ApiRequestError(
62
- "高德 API 返回了非 JSON 响应。",
63
- details={"body": body[:500]},
64
- ) from exc
60
+ try:
61
+ payload = json.loads(body)
62
+ except json.JSONDecodeError as exc:
63
+ raise ApiRequestError(
64
+ "高德 API 返回了非 JSON 响应。",
65
+ details={"body": body[:500]},
66
+ ) from exc
65
67
 
66
- self._raise_for_amap_error(payload)
67
- return payload
68
+ self._raise_for_amap_error(payload)
69
+ return payload
70
+ finally:
71
+ if self.config.request_sleep_seconds > 0:
72
+ time.sleep(self.config.request_sleep_seconds)
68
73
 
69
74
  def _build_url(self, path: str, params: dict[str, Any]) -> str:
70
75
  """Build a full request URL from config and query params."""
@@ -56,6 +56,11 @@ def _register_config_command(
56
56
  type=float,
57
57
  help="请求超时时间(秒)",
58
58
  )
59
+ set_parser.add_argument(
60
+ "--request-sleep-seconds",
61
+ type=float,
62
+ help="每次高德 API 调用结束后的 sleep 时间(秒,0 表示关闭)",
63
+ )
59
64
  set_parser.set_defaults(handler=_handle_config_set)
60
65
 
61
66
  show_parser = config_subparsers.add_parser("show", help="查看当前配置(敏感信息脱敏)")
@@ -73,15 +78,17 @@ def _handle_config_set(args: argparse.Namespace) -> dict[str, Any]:
73
78
  args.api_key is None
74
79
  and args.base_url is None
75
80
  and args.timeout_seconds is None
81
+ and args.request_sleep_seconds is None
76
82
  ):
77
83
  raise ValidationError(
78
- "请至少提供一个配置项,例如 `--api-key`、`--base-url` 或 `--timeout-seconds`。"
84
+ "请至少提供一个配置项,例如 `--api-key`、`--base-url`、`--timeout-seconds` 或 `--request-sleep-seconds`。"
79
85
  )
80
86
 
81
87
  config = save_config(
82
88
  api_key=args.api_key,
83
89
  base_url=args.base_url,
84
90
  timeout_seconds=args.timeout_seconds,
91
+ request_sleep_seconds=args.request_sleep_seconds,
85
92
  )
86
93
  return {
87
94
  "message": "配置已保存。",
@@ -15,6 +15,7 @@ APP_NAME = "amap-cli"
15
15
  CONFIG_FILE_NAME = "config.json"
16
16
  DEFAULT_BASE_URL = "https://restapi.amap.com"
17
17
  DEFAULT_TIMEOUT_SECONDS = 10.0
18
+ DEFAULT_REQUEST_SLEEP_SECONDS = 0.34
18
19
 
19
20
 
20
21
  @dataclass(slots=True)
@@ -24,6 +25,7 @@ class AmapConfig:
24
25
  api_key: str | None = None
25
26
  base_url: str = DEFAULT_BASE_URL
26
27
  timeout_seconds: float = DEFAULT_TIMEOUT_SECONDS
28
+ request_sleep_seconds: float = DEFAULT_REQUEST_SLEEP_SECONDS
27
29
 
28
30
  @classmethod
29
31
  def from_dict(cls, raw: dict[str, Any]) -> "AmapConfig":
@@ -31,6 +33,10 @@ class AmapConfig:
31
33
  api_key = raw.get("api_key")
32
34
  base_url = raw.get("base_url", DEFAULT_BASE_URL)
33
35
  timeout_seconds = raw.get("timeout_seconds", DEFAULT_TIMEOUT_SECONDS)
36
+ request_sleep_seconds = raw.get(
37
+ "request_sleep_seconds",
38
+ DEFAULT_REQUEST_SLEEP_SECONDS,
39
+ )
34
40
 
35
41
  if api_key is not None and not isinstance(api_key, str):
36
42
  raise ConfigError("配置文件中的 api_key 格式无效。")
@@ -38,6 +44,11 @@ class AmapConfig:
38
44
  raise ConfigError("配置文件中的 base_url 格式无效。")
39
45
  if not isinstance(timeout_seconds, (int, float)) or timeout_seconds <= 0:
40
46
  raise ConfigError("配置文件中的 timeout_seconds 格式无效。")
47
+ if (
48
+ not isinstance(request_sleep_seconds, (int, float))
49
+ or request_sleep_seconds < 0
50
+ ):
51
+ raise ConfigError("配置文件中的 request_sleep_seconds 格式无效。")
41
52
 
42
53
  normalized_api_key = None
43
54
  if api_key is not None:
@@ -47,6 +58,7 @@ class AmapConfig:
47
58
  api_key=normalized_api_key,
48
59
  base_url=base_url.strip(),
49
60
  timeout_seconds=float(timeout_seconds),
61
+ request_sleep_seconds=float(request_sleep_seconds),
50
62
  )
51
63
 
52
64
  def to_dict(self, *, mask_secrets: bool = False) -> dict[str, Any]:
@@ -149,6 +161,7 @@ def save_config(
149
161
  api_key: str | None = None,
150
162
  base_url: str | None = None,
151
163
  timeout_seconds: float | None = None,
164
+ request_sleep_seconds: float | None = None,
152
165
  ) -> AmapConfig:
153
166
  """Persist config updates to the OS-specific config path."""
154
167
  config = load_config(required=False) or AmapConfig()
@@ -170,6 +183,11 @@ def save_config(
170
183
  raise ValidationError("`--timeout-seconds` 必须大于 0。")
171
184
  config.timeout_seconds = float(timeout_seconds)
172
185
 
186
+ if request_sleep_seconds is not None:
187
+ if request_sleep_seconds < 0:
188
+ raise ValidationError("`--request-sleep-seconds` 不能小于 0。")
189
+ config.request_sleep_seconds = float(request_sleep_seconds)
190
+
173
191
  path = get_config_path()
174
192
  try:
175
193
  path.parent.mkdir(parents=True, exist_ok=True)
@@ -4,5 +4,5 @@ requires-python = ">=3.11"
4
4
 
5
5
  [[package]]
6
6
  name = "amap-cli"
7
- version = "0.1.3"
7
+ version = "0.1.4"
8
8
  source = { editable = "." }
File without changes
File without changes
File without changes
File without changes