Coverage for youversion/models/base.py: 100%
13 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-06-26 11:31 +0100
« prev ^ index » next coverage.py v7.14.3, created at 2026-06-26 11:31 +0100
1from typing import Any, Protocol
3try:
4 from typing import TypeAlias
5except ImportError:
6 # Python < 3.10 compatibility
7 from typing import TypeAlias
10class ReferenceProtocol(Protocol):
11 """Protocol for YouVersion Bible references."""
13 version_id: str | int
14 human: str
15 usfm: str | list[str]
17 def __getattr__(self, name: str) -> Any:
18 """Allow access to dynamically added fields."""
19 class_name = self.__class__.__name__
20 raise AttributeError(f"'{class_name}' has no attribute '{name}'")
23# Type alias for convenience
24Reference: TypeAlias = ReferenceProtocol
27class MomentProtocol(Protocol):
28 """Protocol for dynamically created moment objects from YouVersion API.
30 This protocol describes the structure of moments returned by the API,
31 allowing type checkers to understand the expected fields while
32 supporting dynamically generated dataclasses.
33 """
35 # Core moment fields
36 id: int
37 kind_id: str
38 kind_color: str | None
39 created_dt: str | None # ISO datetime string
40 updated_dt: str | None # ISO datetime string
42 # Base moment information
43 base: dict[str, Any] | None
44 # base structure typically contains:
45 # - title: dict with l_str and l_args
46 # - body: Optional[str]
47 # - images: dict with avatar, icon, body
48 # - action_url: Optional[str]
49 # - share_url: Optional[str]
51 # Extras information (varies by moment type)
52 extras: dict[str, Any] | None
53 # extras structure typically contains:
54 # - user: dict with id, username, name, avatar
55 # - title: Optional[str]
56 # - content: Optional[str]
57 # - color: Optional[str]
58 # - references: Optional[list[dict]] with usfm, version_id, human
59 # - user_status: Optional[str]
60 # - system_status: Optional[str]
61 # - language_tag: Optional[str]
62 # - labels: Optional[list]
64 # Commenting information
65 commenting: dict[str, Any] | None
66 # commenting structure:
67 # - enabled: bool
68 # - total: int
69 # - comments: Optional[list]
71 # Liking information
72 liking: dict[str, Any] | None
73 # liking structure:
74 # - enabled: bool
75 # - total: int
76 # - likes: Optional[list]
77 # - all_users: Optional[list]
79 def __getattr__(self, name: str) -> Any:
80 """Allow access to dynamically added fields.
82 This enables the protocol to work with dynamically generated
83 dataclasses that may have additional fields not defined here.
84 """
85 class_name = self.__class__.__name__
86 raise AttributeError(f"'{class_name}' has no attribute '{name}'")
89# Type alias for convenience
90Moment: TypeAlias = MomentProtocol