refactor(settings): unify config.py, mconfig.py, and settings.py into single PrySettings
- Merge all configuration into settings.py with PRY_* env var prefix. - Add legacy env aliases (PROXY_URL, TOR_ENABLED, MAX_RETRIES, etc.) for migration. - Load and persist runtime overrides from JSON config file (default /app/config.json). - Update scraper.py, deps.py, routers/config.py to use unified settings. - Add resolved_proxy_chain and resolved_proxy_url properties. - Replace tests/test_mconfig.py with tests/test_settings.py (9 tests). - Update .env.example with new PRY_* options. - All 500 tests pass; ruff clean.
This commit is contained in:
parent
ecb05bbf49
commit
1f9e71d294
9 changed files with 424 additions and 316 deletions
|
|
@ -1,47 +0,0 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
# Copyright (c) 2026 Rug Munch Media LLC
|
||||
#
|
||||
# Part of Pry — https://git.rugmunch.io/RugMunchMedia/pryscraper
|
||||
# Licensed under MIT. See LICENSE.
|
||||
"""Tests for Pry config."""
|
||||
|
||||
from mconfig import PryConfig
|
||||
|
||||
|
||||
def test_config_get_default() -> None:
|
||||
c = PryConfig()
|
||||
assert c.get("nonexistent.key", "fallback") == "fallback"
|
||||
|
||||
|
||||
def test_config_get_retry_exists() -> None:
|
||||
c = PryConfig()
|
||||
val = c.get("retry.max_attempts")
|
||||
assert isinstance(val, int)
|
||||
assert val > 0
|
||||
|
||||
|
||||
def test_config_get_rate_limit_exists() -> None:
|
||||
c = PryConfig()
|
||||
val = c.get("rate_limit.rpm")
|
||||
assert isinstance(val, int)
|
||||
assert val > 0
|
||||
|
||||
|
||||
def test_config_to_dict_excludes_private() -> None:
|
||||
c = PryConfig()
|
||||
d = c.to_dict()
|
||||
assert "_proxy_chain" not in d
|
||||
assert "_proxy_url" not in d
|
||||
|
||||
|
||||
def test_config_update_returns_ok() -> None:
|
||||
c = PryConfig()
|
||||
result = c.update({"retry": {"max_attempts": 5}})
|
||||
assert result["status"] == "ok"
|
||||
assert c.get("retry.max_attempts") == 5
|
||||
|
||||
|
||||
def test_config_get_proxy_url_string_or_none() -> None:
|
||||
c = PryConfig()
|
||||
url = c.get_proxy_url()
|
||||
assert url is None or isinstance(url, str)
|
||||
93
tests/test_settings.py
Normal file
93
tests/test_settings.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
# Copyright (c) 2026 Rug Munch Media LLC
|
||||
#
|
||||
# Part of Pry — https://git.rugmunch.io/RugMunchMedia/pryscraper
|
||||
# Licensed under MIT. See LICENSE.
|
||||
"""Tests for unified Pry settings."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from settings import _NESTED_KEY_MAP, PrySettings
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def isolated_settings(tmp_path: Path) -> PrySettings:
|
||||
"""Return a fresh settings instance with a temp config file."""
|
||||
config_file = tmp_path / "config.json"
|
||||
return PrySettings(config_file=config_file)
|
||||
|
||||
|
||||
def test_settings_get_default(isolated_settings: PrySettings) -> None:
|
||||
assert isolated_settings.max_retries == 3
|
||||
assert isolated_settings.rate_limit_rpm == 120
|
||||
|
||||
|
||||
def test_settings_proxy_resolution(isolated_settings: PrySettings) -> None:
|
||||
assert isolated_settings.resolved_proxy_url is None
|
||||
isolated_settings.proxy_enabled = True
|
||||
isolated_settings.proxy_url = "http://proxy.example:8080"
|
||||
assert isolated_settings.resolved_proxy_url == "http://proxy.example:8080"
|
||||
|
||||
|
||||
def test_settings_tor_chain(isolated_settings: PrySettings) -> None:
|
||||
isolated_settings.tor_enabled = True
|
||||
isolated_settings.proxy_enabled = True
|
||||
isolated_settings.proxy_url = "http://proxy.example:8080"
|
||||
chain = isolated_settings.resolved_proxy_chain
|
||||
assert len(chain) == 2
|
||||
assert chain[0].startswith("socks5://")
|
||||
|
||||
|
||||
def test_settings_to_api_dict_excludes_private(isolated_settings: PrySettings) -> None:
|
||||
data = isolated_settings.to_api_dict()
|
||||
assert "_proxy_chain" not in data
|
||||
assert "proxy" in data
|
||||
assert isinstance(data["proxy"]["enabled"], bool)
|
||||
|
||||
|
||||
def test_settings_update_and_persist(isolated_settings: PrySettings) -> None:
|
||||
result = isolated_settings.update({"retry": {"max_attempts": 5}})
|
||||
assert result["status"] == "ok"
|
||||
assert isolated_settings.max_retries == 5
|
||||
assert isolated_settings.config_file.exists()
|
||||
saved = json.loads(isolated_settings.config_file.read_text(encoding="utf-8"))
|
||||
assert saved["retry"]["max_attempts"] == 5
|
||||
|
||||
|
||||
def test_settings_load_config_file(tmp_path: Path) -> None:
|
||||
config_file = tmp_path / "config.json"
|
||||
config_file.write_text(
|
||||
json.dumps({"retry": {"max_attempts": 7}, "tor": {"enabled": True}}),
|
||||
encoding="utf-8",
|
||||
)
|
||||
s = PrySettings(config_file=config_file)
|
||||
assert s.max_retries == 7
|
||||
assert s.tor_enabled is True
|
||||
|
||||
|
||||
def test_settings_legacy_env_vars(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||
monkeypatch.setenv("PROXY_URL", "http://legacy-proxy:8080")
|
||||
monkeypatch.setenv("TOR_ENABLED", "true")
|
||||
monkeypatch.setenv("MAX_RETRIES", "9")
|
||||
config_file = tmp_path / "config.json"
|
||||
s = PrySettings(config_file=config_file)
|
||||
assert s.proxy_url == "http://legacy-proxy:8080"
|
||||
assert s.tor_enabled is True
|
||||
assert s.max_retries == 9
|
||||
|
||||
|
||||
def test_settings_enable_tor(isolated_settings: PrySettings) -> None:
|
||||
result = isolated_settings.enable_tor()
|
||||
assert result["status"] == "ok"
|
||||
assert isolated_settings.tor_enabled is True
|
||||
assert isolated_settings.proxy_enabled is True
|
||||
assert isolated_settings.proxy_url == "socks5://tor:9050"
|
||||
|
||||
|
||||
def test_nested_key_map_complete() -> None:
|
||||
"""Ensure every API-facing nested key maps to a settings attribute."""
|
||||
for attr in _NESTED_KEY_MAP.values():
|
||||
assert attr in PrySettings.model_fields, f"PrySettings missing {attr}"
|
||||
Loading…
Add table
Add a link
Reference in a new issue