- Fix memory test infinite loop (#1, #3) — add max iterations counter - Fix os.system command injection (#2, #4) — use subprocess with list args - Fix demon difficulty scaling (#5) — scale health/damage per cycle - Fix relative import (#6) — absolute imports with sys.path fallback - Fix normalize_text non-ASCII (#7) — use isalpha/isdigit instead of isalnum - Fix calculate_similarity word order (#8) — set-based intersection - Add CMD to Dockerfile (#9) - Remove test files from prod image (#10) — .dockerignore + strip tests COPY - Fix test class import (#11) — lazy import in test methods - Fix pyproject.toml duplicate pytest (#12) — move to dev optional deps - Add resource limits to compose (#13) - Fix verses.json quality (#14) — fix garbled verse text
96 lines
2.5 KiB
Python
96 lines
2.5 KiB
Python
"""Data module for loading and managing Bible verse data."""
|
|
|
|
import json
|
|
import os
|
|
from typing import Any
|
|
|
|
|
|
def load_verses() -> list[dict[str, Any]]:
|
|
"""Load verses from the verses.json file.
|
|
|
|
Returns:
|
|
List of verse dictionaries with id, text, category, difficulty, reference.
|
|
"""
|
|
verses_path = os.path.join(os.path.dirname(__file__), "verses.json")
|
|
with open(verses_path) as f:
|
|
data = json.load(f)
|
|
return data["verses"]
|
|
|
|
|
|
def get_verses_by_category(verses: list[dict[str, Any]], category: str) -> list[dict[str, Any]]:
|
|
"""Filter verses by category (case-insensitive).
|
|
|
|
Args:
|
|
verses: List of all verses.
|
|
category: Category name to filter by.
|
|
|
|
Returns:
|
|
List of verses matching the category.
|
|
"""
|
|
return [v for v in verses if v["category"].lower() == category.lower()]
|
|
|
|
|
|
def get_verses_by_max_difficulty(
|
|
verses: list[dict[str, Any]], max_difficulty: int
|
|
) -> list[dict[str, Any]]:
|
|
"""Filter verses by maximum difficulty level.
|
|
|
|
Args:
|
|
verses: List of all verses.
|
|
max_difficulty: Maximum difficulty level to include.
|
|
|
|
Returns:
|
|
List of verses with difficulty <= max_difficulty.
|
|
"""
|
|
return [v for v in verses if v["difficulty"] <= max_difficulty]
|
|
|
|
|
|
def normalize_text(text: str) -> str:
|
|
"""Normalize text for comparison.
|
|
|
|
Removes punctuation, lowers case, and collapses whitespace.
|
|
|
|
Args:
|
|
text: Raw text string to normalize.
|
|
|
|
Returns:
|
|
Normalized string with no punctuation, lowercase, single spaces.
|
|
"""
|
|
result = []
|
|
for char in text.lower():
|
|
if char.isalpha() or char.isdigit() or char.isspace():
|
|
result.append(char)
|
|
normalized = "".join(result)
|
|
return " ".join(normalized.split())
|
|
|
|
|
|
def get_verse_by_id(verses: list[dict[str, Any]], verse_id: str) -> dict[str, Any] | None:
|
|
"""Find a verse by its unique ID.
|
|
|
|
Args:
|
|
verses: List of all verses.
|
|
verse_id: The unique ID string of the verse.
|
|
|
|
Returns:
|
|
The verse dictionary if found, None otherwise.
|
|
"""
|
|
for verse in verses:
|
|
if verse["id"] == verse_id:
|
|
return verse
|
|
return None
|
|
|
|
|
|
def get_categories(verses: list[dict[str, Any]]) -> list[str]:
|
|
"""Get a list of unique categories from the verses.
|
|
|
|
Args:
|
|
verses: List of all verses.
|
|
|
|
Returns:
|
|
Sorted list of unique category names.
|
|
"""
|
|
categories = set()
|
|
for verse in verses:
|
|
categories.add(verse["category"])
|
|
return sorted(categories)
|