From 4ae53c27253a1633a14adc39a3e007c6b7fb9830 Mon Sep 17 00:00:00 2001 From: Kenichiro NOGI Date: Sun, 2 Aug 2026 10:08:02 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20config.txt=E8=AA=AD=E8=BE=BC=E3=83=A2?= =?UTF-8?q?=E3=82=B8=E3=83=A5=E3=83=BC=E3=83=AB=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../ScanOCR/スクリプト/config_loader.py | 45 +++++++++++++++ .../スクリプト/tests/test_config_loader.py | 55 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 PythonProj/ScanOCR/スクリプト/config_loader.py create mode 100644 PythonProj/ScanOCR/スクリプト/tests/test_config_loader.py diff --git a/PythonProj/ScanOCR/スクリプト/config_loader.py b/PythonProj/ScanOCR/スクリプト/config_loader.py new file mode 100644 index 00000000..72d6797e --- /dev/null +++ b/PythonProj/ScanOCR/スクリプト/config_loader.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +"""config.txt(key=value形式)読込モジュール。""" +from __future__ import annotations + +from pathlib import Path + + +class ConfigError(Exception): + pass + + +REQUIRED_KEYS = ( + "スクリプトフォルダ", + "テンプレートフォルダ", + "スキャンフォルダ", + "アウトプットフォルダ", + "成功フォルダ", + "失敗フォルダ", + "ログフォルダ", + "margin", + "DPI", + "ファイル安定待ち秒", + "ファイル安定待ちリトライ回数", +) + + +def load_config(config_path: Path) -> dict[str, str]: + if not config_path.exists(): + raise ConfigError(f"config.txt が見つかりません: {config_path}") + + config: dict[str, str] = {} + for raw_line in config_path.read_text(encoding="utf-8").splitlines(): + line = raw_line.strip() + if not line or line.startswith("#") or "=" not in line: + continue + key, _, value = line.partition("=") + config[key.strip()] = value.strip() + + missing = [key for key in REQUIRED_KEYS if key not in config] + if missing: + raise ConfigError( + f"config.txt に必須項目が不足しています: {', '.join(missing)}" + ) + + return config diff --git a/PythonProj/ScanOCR/スクリプト/tests/test_config_loader.py b/PythonProj/ScanOCR/スクリプト/tests/test_config_loader.py new file mode 100644 index 00000000..5c42cf09 --- /dev/null +++ b/PythonProj/ScanOCR/スクリプト/tests/test_config_loader.py @@ -0,0 +1,55 @@ +import pytest +from pathlib import Path + +from config_loader import ConfigError, load_config + + +VALID_CONTENT = """\ +スクリプトフォルダ=スクリプト +テンプレートフォルダ=テンプレート +スキャンフォルダ=スキャン +アウトプットフォルダ=アウトプット +成功フォルダ=成功 +失敗フォルダ=失敗 +ログフォルダ=ログ +margin=0.10 +DPI=300 +ファイル安定待ち秒=1 +ファイル安定待ちリトライ回数=5 +""" + + +def test_load_config_missing_file_raises(tmp_path): + missing_path = tmp_path / "config.txt" + with pytest.raises(ConfigError): + load_config(missing_path) + + +def test_load_config_parses_all_keys(tmp_path): + config_path = tmp_path / "config.txt" + config_path.write_text(VALID_CONTENT, encoding="utf-8") + + config = load_config(config_path) + + assert config["スクリプトフォルダ"] == "スクリプト" + assert config["テンプレートフォルダ"] == "テンプレート" + assert config["margin"] == "0.10" + assert config["ファイル安定待ちリトライ回数"] == "5" + + +def test_load_config_missing_required_key_raises(tmp_path): + config_path = tmp_path / "config.txt" + config_path.write_text("スクリプトフォルダ=スクリプト\n", encoding="utf-8") + + with pytest.raises(ConfigError): + load_config(config_path) + + +def test_load_config_ignores_blank_lines_and_comments(tmp_path): + config_path = tmp_path / "config.txt" + content = "# comment\n\n" + VALID_CONTENT + config_path.write_text(content, encoding="utf-8") + + config = load_config(config_path) + + assert config["スクリプトフォルダ"] == "スクリプト"