Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Tests for Settings field validators."""

import pytest
from pydantic import ValidationError

from token0.config import Settings


def test_storage_mode_valid_values():
assert Settings(storage_mode="lite").storage_mode == "lite"
assert Settings(storage_mode="full").storage_mode == "full"


def test_storage_mode_invalid_raises():
with pytest.raises(ValidationError):
Settings(storage_mode="prod")


def test_text_density_threshold_valid():
assert Settings(text_density_threshold=0.0).text_density_threshold == 0.0
assert Settings(text_density_threshold=1.0).text_density_threshold == 1.0
assert Settings(text_density_threshold=0.52).text_density_threshold == 0.52


def test_text_density_threshold_out_of_range_raises():
with pytest.raises(ValidationError):
Settings(text_density_threshold=1.1)
with pytest.raises(ValidationError):
Settings(text_density_threshold=-0.1)


def test_port_valid():
assert Settings(port=8000).port == 8000
assert Settings(port=1).port == 1
assert Settings(port=65535).port == 65535


def test_port_out_of_range_raises():
with pytest.raises(ValidationError):
Settings(port=0)
with pytest.raises(ValidationError):
Settings(port=65536)
19 changes: 18 additions & 1 deletion token0/config.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from typing import Literal

from pydantic import field_validator
from pydantic_settings import BaseSettings


class Settings(BaseSettings):
# Storage mode: "lite" (SQLite + in-memory) or "full" (Postgres + Redis + S3)
# Use "lite" for local dev/testing, "full" for production
storage_mode: str = "lite"
storage_mode: Literal["lite", "full"] = "lite"

# Database — only needed in full mode
database_url: str = "postgresql+asyncpg://token0:token0@localhost:5432/token0"
Expand Down Expand Up @@ -40,6 +43,20 @@ class Settings(BaseSettings):
jpeg_quality: int = 85
text_density_threshold: float = 0.52 # Above this → OCR route instead of vision

@field_validator("text_density_threshold")
@classmethod
def validate_threshold(cls, v: float) -> float:
Comment thread
Pritom14 marked this conversation as resolved.
if not 0.0 <= v <= 1.0:
raise ValueError(f"text_density_threshold must be between 0.0 and 1.0, got {v}")
return v

@field_validator("port")
@classmethod
def validate_port(cls, v: int) -> int:
if not 1 <= v <= 65535:
raise ValueError(f"port must be between 1 and 65535, got {v}")
return v

@property
def is_lite(self) -> bool:
return self.storage_mode == "lite"
Expand Down
Loading