From cf651988251986caf4748ff30c388e6b3d9f6b5c Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 27 Jul 2026 09:21:52 +1000 Subject: [PATCH] fix: accept CSV telegram ID config (#27) Co-authored-by: openhands --- AGENTS.md | 2 +- CONFIGURATION.md | 10 +++---- steward/config.py | 43 +++++++++++++++++++++++++++--- tests/test_config.py | 63 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 tests/test_config.py diff --git a/AGENTS.md b/AGENTS.md index d04e541..05be289 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -263,7 +263,7 @@ Note: Pre-commit will run these checks automatically on commit, so you usually d **Configuration issues:** 1. Check `.env` file syntax (should be `KEY=value`) -2. For lists, use JSON format: `STEWARD__TELEGRAM__ALLOWED_USER_IDS='[123, 456]'` +2. For lists, prefer CSV format: `STEWARD__TELEGRAM__ALLOWED_USER_IDS=123,456` (JSON lists are also supported) 3. New format variables use `STEWARD__SECTION__KEY` pattern 4. Check `CONFIGURATION.md` for examples diff --git a/CONFIGURATION.md b/CONFIGURATION.md index ae5498d..b19bb3f 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -141,8 +141,8 @@ telegram: **Environment Variables:** - `STEWARD__TELEGRAM__BOT_TOKEN` - Telegram bot token (REQUIRED) -- `STEWARD__TELEGRAM__ALLOWED_USER_IDS` - JSON list: `[123,456,789]` -- `STEWARD__TELEGRAM__GROUP_IDS` - JSON list: `[-1005308306472]` +- `STEWARD__TELEGRAM__ALLOWED_USER_IDS` - Comma-separated or JSON list: `123,456,789` +- `STEWARD__TELEGRAM__GROUP_IDS` - Comma-separated or JSON list: `-1005308306472` ### OpenAI Section @@ -211,10 +211,10 @@ STEWARD__OPENAI__MODEL="gpt-4-turbo" STEWARD__ANALYSIS__CRON_HOUR="9" ``` -For list values, use JSON format: +For list values, use comma-separated integers. JSON lists are also accepted for compatibility: ```bash -STEWARD__TELEGRAM__ALLOWED_USER_IDS='[123456789, 987654321]' -STEWARD__TELEGRAM__GROUP_IDS='[-1005308306472]' +STEWARD__TELEGRAM__ALLOWED_USER_IDS=123456789,987654321 +STEWARD__TELEGRAM__GROUP_IDS=-1005308306472 ``` ## Best Practices diff --git a/steward/config.py b/steward/config.py index 2bfd70e..4a04dcc 100644 --- a/steward/config.py +++ b/steward/config.py @@ -8,16 +8,50 @@ Supports configuration via: Environment variables take precedence over config file values. """ +import json import logging import os from pathlib import Path +from typing import Any from omegaconf import OmegaConf -from pydantic import BaseModel, ConfigDict, Field +from pydantic import BaseModel, ConfigDict, Field, field_validator logger = logging.getLogger(__name__) +def _parse_int_list(value: Any) -> Any: + if isinstance(value, int): + return [value] + if not isinstance(value, str): + return value + + text = value.strip() + if not text: + return [] + + if len(text) >= 2 and text[0] == text[-1] and text[0] in {"'", '"'}: + text = text[1:-1].strip() + if not text: + return [] + + if text.startswith("["): + try: + parsed = json.loads(text) + except json.JSONDecodeError: + pass + else: + if isinstance(parsed, list): + return parsed + + try: + return [int(item.strip().strip("'\"")) for item in text.split(",") if item.strip()] + except ValueError as exc: + raise ValueError( + "expected a comma-separated list of integers or a JSON integer list" + ) from exc + + class TelegramConfig(BaseModel): """Telegram bot configuration.""" @@ -25,6 +59,11 @@ class TelegramConfig(BaseModel): allowed_user_ids: list[int] = Field(default_factory=list, description="Allowed user IDs") group_ids: list[int] = Field(default_factory=list, description="Allowed group/channel IDs") + @field_validator("allowed_user_ids", "group_ids", mode="before") + @classmethod + def parse_int_list(cls, value: Any) -> Any: + return _parse_int_list(value) + class OpenAIConfig(BaseModel): """OpenAI/LLM configuration.""" @@ -186,8 +225,6 @@ def _load_config_from_env() -> dict: # Try to parse value as JSON first (for lists, etc.) if isinstance(cfg[section], dict): try: - import json - cfg[section][setting_key] = json.loads(value) except (json.JSONDecodeError, ValueError): cfg[section][setting_key] = value diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..44349cd --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,63 @@ +"""Tests for Steward configuration loading.""" + +import pytest + +from steward import config as config_module +from steward.config import TelegramConfig, reload_settings + + +@pytest.fixture(autouse=True) +def reset_settings_singleton(): + config_module._settings_instance = None + yield + config_module._settings_instance = None + + +def test_telegram_config_accepts_csv_id_lists(): + config = TelegramConfig( + allowed_user_ids="8861600138, 123456789", + group_ids="-5308306472,-1005308306472", + ) + + assert config.allowed_user_ids == [8861600138, 123456789] + assert config.group_ids == [-5308306472, -1005308306472] + + +def test_telegram_config_preserves_list_id_values(): + config = TelegramConfig( + allowed_user_ids=[8861600138, 123456789], + group_ids=[-5308306472, -1005308306472], + ) + + assert config.allowed_user_ids == [8861600138, 123456789] + assert config.group_ids == [-5308306472, -1005308306472] + + +def test_settings_accepts_csv_id_lists_from_env(monkeypatch): + monkeypatch.setenv("STEWARD__TELEGRAM__ALLOWED_USER_IDS", "8861600138,123456789") + monkeypatch.setenv("STEWARD__TELEGRAM__GROUP_IDS", "-5308306472,-1005308306472") + + settings = reload_settings() + + assert settings.telegram_allowed_user_ids == [8861600138, 123456789] + assert settings.telegram_group_ids == [-5308306472, -1005308306472] + + +def test_settings_accepts_single_id_values_from_env(monkeypatch): + monkeypatch.setenv("STEWARD__TELEGRAM__ALLOWED_USER_IDS", "8861600138") + monkeypatch.setenv("STEWARD__TELEGRAM__GROUP_IDS", "-5308306472") + + settings = reload_settings() + + assert settings.telegram_allowed_user_ids == [8861600138] + assert settings.telegram_group_ids == [-5308306472] + + +def test_settings_accepts_quoted_json_id_lists_from_env(monkeypatch): + monkeypatch.setenv("STEWARD__TELEGRAM__ALLOWED_USER_IDS", "'[8861600138]'") + monkeypatch.setenv("STEWARD__TELEGRAM__GROUP_IDS", "'[-5308306472]'") + + settings = reload_settings() + + assert settings.telegram_allowed_user_ids == [8861600138] + assert settings.telegram_group_ids == [-5308306472]