Coverage for src / beautyspot / __init__.py: 96%
39 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-03-11 19:10 +0900
« prev ^ index » next coverage.py v7.13.2, created at 2026-03-11 19:10 +0900
1# src/beautyspot/__init__.py
3import logging
4from importlib.metadata import version, PackageNotFoundError
5from pathlib import Path
6from typing import Optional, Callable
8from beautyspot.core import Spot as _Spot
9from beautyspot.cache import CacheManager as _CacheManager
11from beautyspot.types import (
12 SaveErrorContext,
13 PreExecuteContext,
14 CacheHitContext,
15 CacheMissContext,
16)
17from beautyspot.cachekey import KeyGen
18from beautyspot.lifecycle import LifecyclePolicy, Rule, Retention
19from beautyspot.limiter import TokenBucket, LimiterProtocol
20from beautyspot.content_types import ContentType
21from beautyspot.db import TaskDBBase, TaskDBCore, TaskDBMaintenable, SQLiteTaskDB
22from beautyspot.exceptions import (
23 BeautySpotError,
24 CacheCorruptedError,
25 SerializationError,
26 ConfigurationError,
27 ValidationError,
28 IncompatibleProviderError,
29)
30from beautyspot.storage import (
31 BlobStorageBase,
32 BlobStorageCore,
33 BlobStorageMaintenable,
34 LocalStorage,
35 StoragePolicyProtocol,
36 WarningOnlyPolicy,
37 ThresholdStoragePolicy,
38 AlwaysBlobPolicy,
39)
40from beautyspot.serializer import SerializerProtocol, MsgpackSerializer
41from beautyspot.hooks import HookBase, ThreadSafeHookBase
43try:
44 __version__ = version("beautyspot")
45except PackageNotFoundError:
46 __version__ = "0.0.0+unknown"
49def Spot(
50 name: str,
51 db: Optional[TaskDBMaintenable] = None,
52 serializer: Optional[SerializerProtocol] = None,
53 limiter: Optional[LimiterProtocol] = None,
54 storage_backend: Optional[BlobStorageMaintenable] = None,
55 storage_policy: Optional[StoragePolicyProtocol] = None,
56 cache: Optional[_CacheManager] = None,
57 # --- Configuration Options ---
58 lifecycle_policy: Optional[LifecyclePolicy] = None,
59 eviction_rate: float = 0.0,
60 blob_warning_threshold: int = 1024 * 1024,
61 save_blob: bool = False,
62 tpm: int = 10000,
63 save_sync: bool = True,
64 drain_timeout: float = 5.0,
65 drain_poll_interval: float = 0.5,
66 on_background_error: Optional[Callable[[BaseException, SaveErrorContext], None]] = None,
67) -> _Spot:
68 """
69 Beautyspotのメインエントリポイント(Factory Function)。
70 依存関係の解決とデフォルト設定の適用を行います。
71 """
73 # 0. デフォルトパス使用時のみワークスペースをセットアップ
74 _default_workspace = Path(".beautyspot")
76 # 1. コンポーネントの解決 (DI)
77 resolved_db = db or SQLiteTaskDB(_default_workspace / f"{name}.db")
78 resolved_ser = serializer or MsgpackSerializer()
79 resolved_stg = storage_backend or LocalStorage(_default_workspace / "blobs" / name)
80 resolved_limiter = limiter or TokenBucket(tokens_per_minute=tpm)
82 # 2. Storage Policy の解決
83 resolved_policy: StoragePolicyProtocol
84 if storage_policy is not None:
85 resolved_policy = storage_policy
86 elif save_blob:
87 resolved_policy = AlwaysBlobPolicy()
88 else:
89 logger = logging.getLogger("beautyspot")
90 resolved_policy = WarningOnlyPolicy(
91 warning_threshold=blob_warning_threshold, logger=logger
92 )
94 # 3. CacheManager の組み立て (Composition)
95 resolved_cache = cache or _CacheManager(
96 db=resolved_db,
97 storage=resolved_stg,
98 serializer=resolved_ser,
99 storage_policy=resolved_policy,
100 lifecycle_policy=lifecycle_policy,
101 )
103 # 4. Core Spot の生成
104 spot = _Spot(
105 name=name,
106 cache=resolved_cache,
107 limiter=resolved_limiter,
108 # その他のオプション
109 save_sync=save_sync,
110 eviction_rate=eviction_rate,
111 drain_timeout=drain_timeout,
112 drain_poll_interval=drain_poll_interval,
113 on_background_error=on_background_error,
114 )
116 # ファクトリ関数で内部的に DB を生成した場合のみ、GC 時にシャットダウンする。
117 # ユーザーが明示的に db= を渡した場合はライフサイクルを呼び出し元に委ねる。
118 if db is None:
119 spot._owns_db = True
121 return spot
124# isinstance(spot, bs.SpotType) のための型エクスポート
125SpotType: type[_Spot] = _Spot
127__all__ = [
128 # --- Core ---
129 "Spot",
130 "SpotType",
131 "KeyGen",
132 "ContentType",
133 "SaveErrorContext",
134 # --- Exceptions ---
135 "BeautySpotError",
136 "CacheCorruptedError",
137 "SerializationError",
138 "ConfigurationError",
139 "ValidationError",
140 "IncompatibleProviderError",
141 # --- Protocols & Base Classes (for custom implementations) ---
142 "TaskDBCore",
143 "TaskDBMaintenable",
144 "TaskDBBase",
145 "BlobStorageCore",
146 "BlobStorageMaintenable",
147 "BlobStorageBase",
148 "SerializerProtocol",
149 "StoragePolicyProtocol",
150 "LimiterProtocol",
151 # --- Default Implementations ---
152 "SQLiteTaskDB",
153 "LocalStorage",
154 "MsgpackSerializer",
155 "TokenBucket",
156 "ThresholdStoragePolicy",
157 "WarningOnlyPolicy",
158 "AlwaysBlobPolicy",
159 # --- Lifecycle ---
160 "LifecyclePolicy",
161 "Rule",
162 "Retention",
163 # --- Hooks ---
164 "HookBase",
165 "ThreadSafeHookBase",
166 "PreExecuteContext",
167 "CacheHitContext",
168 "CacheMissContext",
169]