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

1# src/beautyspot/__init__.py 

2 

3import logging 

4from importlib.metadata import version, PackageNotFoundError 

5from pathlib import Path 

6from typing import Optional, Callable 

7 

8from beautyspot.core import Spot as _Spot 

9from beautyspot.cache import CacheManager as _CacheManager 

10 

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 

42 

43try: 

44 __version__ = version("beautyspot") 

45except PackageNotFoundError: 

46 __version__ = "0.0.0+unknown" 

47 

48 

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 """ 

72 

73 # 0. デフォルトパス使用時のみワークスペースをセットアップ 

74 _default_workspace = Path(".beautyspot") 

75 

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) 

81 

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 ) 

93 

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 ) 

102 

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 ) 

115 

116 # ファクトリ関数で内部的に DB を生成した場合のみ、GC 時にシャットダウンする。 

117 # ユーザーが明示的に db= を渡した場合はライフサイクルを呼び出し元に委ねる。 

118 if db is None: 

119 spot._owns_db = True 

120 

121 return spot 

122 

123 

124# isinstance(spot, bs.SpotType) のための型エクスポート 

125SpotType: type[_Spot] = _Spot 

126 

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]