zxxxxxxxx commited on
Commit
2bfeaca
·
1 Parent(s): 3f37e67

Handle missing Docker config file mounts

Browse files
Files changed (4) hide show
  1. Dockerfile +1 -0
  2. README.md +2 -0
  3. services/config.py +24 -6
  4. test/test_config.py +64 -0
Dockerfile CHANGED
@@ -31,6 +31,7 @@ COPY pyproject.toml uv.lock ./
31
  RUN uv sync --frozen --no-dev --no-install-project
32
 
33
  COPY main.py ./
 
34
  COPY VERSION ./
35
  COPY services ./services
36
  COPY --from=web-build /app/web/out ./web_dist
 
31
  RUN uv sync --frozen --no-dev --no-install-project
32
 
33
  COPY main.py ./
34
+ COPY config.example.json ./
35
  COPY VERSION ./
36
  COPY services ./services
37
  COPY --from=web-build /app/web/out ./web_dist
README.md CHANGED
@@ -74,6 +74,8 @@ git clone git@github.com:basketikun/chatgpt2api.git
74
  docker compose up -d
75
  ```
76
 
 
 
77
  ## 社区支持
78
  学 AI , 上 L 站
79
 
 
74
  docker compose up -d
75
  ```
76
 
77
+ 如果之前在宿主机上没有 `config.json` 就直接执行了 `docker compose up -d`,Docker 可能会错误地创建一个 `config.json/` 目录。遇到这种情况请先删除这个目录,再重新创建 `config.json` 文件后启动。
78
+
79
  ## 社区支持
80
  学 AI , 上 L 站
81
 
services/config.py CHANGED
@@ -3,6 +3,7 @@ from __future__ import annotations
3
  import json
4
  import os
5
  import shutil
 
6
  from dataclasses import dataclass
7
  from pathlib import Path
8
  from typing import cast
@@ -22,6 +23,19 @@ class AppSettings:
22
  accounts_file: Path
23
  refresh_account_interval_minute: int
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  def _load_json_object(path: Path, *, name: str) -> dict[str, object]:
26
  text = path.read_text(encoding="utf-8").strip()
27
  if not text:
@@ -36,9 +50,10 @@ def _load_json_object(path: Path, *, name: str) -> dict[str, object]:
36
  def _ensure_config_file() -> None:
37
  if CONFIG_FILE.exists():
38
  return
39
- if not CONFIG_EXAMPLE_FILE.exists():
 
40
  return
41
- shutil.copyfile(CONFIG_EXAMPLE_FILE, CONFIG_FILE)
42
 
43
 
44
  def _load_settings() -> AppSettings:
@@ -46,10 +61,13 @@ def _load_settings() -> AppSettings:
46
  _ensure_config_file()
47
 
48
  raw_config: dict[str, object] = {}
49
- if CONFIG_EXAMPLE_FILE.exists():
50
- raw_config.update(_load_json_object(CONFIG_EXAMPLE_FILE, name="config.example.json"))
51
- if CONFIG_FILE.exists():
52
- raw_config.update(_load_json_object(CONFIG_FILE, name="config.json"))
 
 
 
53
 
54
  auth_key = str(os.getenv("CHATGPT2API_AUTH_KEY") or raw_config.get("auth-key") or "").strip()
55
  if not auth_key:
 
3
  import json
4
  import os
5
  import shutil
6
+ import sys
7
  from dataclasses import dataclass
8
  from pathlib import Path
9
  from typing import cast
 
23
  accounts_file: Path
24
  refresh_account_interval_minute: int
25
 
26
+
27
+ def _readable_json_file(path: Path, *, name: str) -> Path | None:
28
+ if not path.exists():
29
+ return None
30
+ if path.is_dir():
31
+ print(
32
+ f"Warning: {name} at '{path}' is a directory, ignoring it and falling back to other configuration sources.",
33
+ file=sys.stderr,
34
+ )
35
+ return None
36
+ return path
37
+
38
+
39
  def _load_json_object(path: Path, *, name: str) -> dict[str, object]:
40
  text = path.read_text(encoding="utf-8").strip()
41
  if not text:
 
50
  def _ensure_config_file() -> None:
51
  if CONFIG_FILE.exists():
52
  return
53
+ example_file = _readable_json_file(CONFIG_EXAMPLE_FILE, name="config.example.json")
54
+ if example_file is None:
55
  return
56
+ shutil.copyfile(example_file, CONFIG_FILE)
57
 
58
 
59
  def _load_settings() -> AppSettings:
 
61
  _ensure_config_file()
62
 
63
  raw_config: dict[str, object] = {}
64
+ example_file = _readable_json_file(CONFIG_EXAMPLE_FILE, name="config.example.json")
65
+ if example_file is not None:
66
+ raw_config.update(_load_json_object(example_file, name="config.example.json"))
67
+
68
+ config_file = _readable_json_file(CONFIG_FILE, name="config.json")
69
+ if config_file is not None:
70
+ raw_config.update(_load_json_object(config_file, name="config.json"))
71
 
72
  auth_key = str(os.getenv("CHATGPT2API_AUTH_KEY") or raw_config.get("auth-key") or "").strip()
73
  if not auth_key:
test/test_config.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import tempfile
3
+ import unittest
4
+ from pathlib import Path
5
+
6
+
7
+ ROOT_DIR = Path(__file__).resolve().parents[1]
8
+ ROOT_CONFIG_FILE = ROOT_DIR / "config.json"
9
+
10
+
11
+ class ConfigLoadingTests(unittest.TestCase):
12
+ @classmethod
13
+ def setUpClass(cls) -> None:
14
+ cls._created_root_config = False
15
+ if not ROOT_CONFIG_FILE.exists():
16
+ ROOT_CONFIG_FILE.write_text(json.dumps({"auth-key": "test-auth"}), encoding="utf-8")
17
+ cls._created_root_config = True
18
+
19
+ from services import config as config_module
20
+
21
+ cls.config_module = config_module
22
+
23
+ @classmethod
24
+ def tearDownClass(cls) -> None:
25
+ if cls._created_root_config and ROOT_CONFIG_FILE.exists():
26
+ ROOT_CONFIG_FILE.unlink()
27
+
28
+ def test_load_settings_falls_back_to_example_when_config_path_is_directory(self) -> None:
29
+ with tempfile.TemporaryDirectory() as tmp_dir:
30
+ base_dir = Path(tmp_dir)
31
+ data_dir = base_dir / "data"
32
+ config_dir = base_dir / "config.json"
33
+ example_file = base_dir / "config.example.json"
34
+
35
+ config_dir.mkdir()
36
+ example_file.write_text(
37
+ json.dumps({"auth-key": "example-auth", "refresh_account_interval_minute": 15}),
38
+ encoding="utf-8",
39
+ )
40
+
41
+ module = self.config_module
42
+ old_base_dir = module.BASE_DIR
43
+ old_data_dir = module.DATA_DIR
44
+ old_config_file = module.CONFIG_FILE
45
+ old_config_example_file = module.CONFIG_EXAMPLE_FILE
46
+ try:
47
+ module.BASE_DIR = base_dir
48
+ module.DATA_DIR = data_dir
49
+ module.CONFIG_FILE = config_dir
50
+ module.CONFIG_EXAMPLE_FILE = example_file
51
+
52
+ settings = module._load_settings()
53
+
54
+ self.assertEqual(settings.auth_key, "example-auth")
55
+ self.assertEqual(settings.refresh_account_interval_minute, 15)
56
+ finally:
57
+ module.BASE_DIR = old_base_dir
58
+ module.DATA_DIR = old_data_dir
59
+ module.CONFIG_FILE = old_config_file
60
+ module.CONFIG_EXAMPLE_FILE = old_config_example_file
61
+
62
+
63
+ if __name__ == "__main__":
64
+ unittest.main()