ErisPulse 2.2.1.dev0__py3-none-any.whl → 2.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. ErisPulse/Core/Bases/__init__.py +14 -0
  2. ErisPulse/Core/Bases/adapter.py +196 -0
  3. ErisPulse/Core/Bases/module.py +54 -0
  4. ErisPulse/Core/Event/__init__.py +14 -0
  5. ErisPulse/Core/Event/base.py +15 -2
  6. ErisPulse/Core/Event/command.py +21 -2
  7. ErisPulse/Core/Event/message.py +15 -0
  8. ErisPulse/Core/Event/meta.py +15 -0
  9. ErisPulse/Core/Event/notice.py +15 -0
  10. ErisPulse/Core/Event/request.py +16 -1
  11. ErisPulse/Core/__init__.py +38 -19
  12. ErisPulse/Core/{erispulse_config.py → _self_config.py} +27 -2
  13. ErisPulse/Core/adapter.py +374 -377
  14. ErisPulse/Core/config.py +137 -38
  15. ErisPulse/Core/exceptions.py +6 -1
  16. ErisPulse/Core/lifecycle.py +167 -0
  17. ErisPulse/Core/logger.py +97 -49
  18. ErisPulse/Core/module.py +279 -56
  19. ErisPulse/Core/router.py +112 -23
  20. ErisPulse/Core/storage.py +258 -77
  21. ErisPulse/Core/ux.py +635 -0
  22. ErisPulse/__init__.py +722 -244
  23. ErisPulse/__main__.py +1 -1999
  24. ErisPulse/utils/__init__.py +17 -0
  25. ErisPulse/utils/cli.py +1092 -0
  26. ErisPulse/utils/console.py +53 -0
  27. ErisPulse/utils/package_manager.py +845 -0
  28. ErisPulse/utils/reload_handler.py +111 -0
  29. {erispulse-2.2.1.dev0.dist-info → erispulse-2.3.0.dist-info}/METADATA +24 -6
  30. erispulse-2.3.0.dist-info/RECORD +34 -0
  31. {erispulse-2.2.1.dev0.dist-info → erispulse-2.3.0.dist-info}/WHEEL +1 -1
  32. {erispulse-2.2.1.dev0.dist-info → erispulse-2.3.0.dist-info}/licenses/LICENSE +1 -1
  33. ErisPulse/Core/env.py +0 -15
  34. ErisPulse/Core/module_registry.py +0 -227
  35. erispulse-2.2.1.dev0.dist-info/RECORD +0 -26
  36. {erispulse-2.2.1.dev0.dist-info → erispulse-2.3.0.dist-info}/entry_points.txt +0 -0
ErisPulse/Core/storage.py CHANGED
@@ -4,6 +4,16 @@ ErisPulse 存储管理模块
4
4
  提供键值存储、事务支持、快照和恢复功能,用于管理框架运行时数据。
5
5
  基于SQLite实现持久化存储,支持复杂数据类型和原子操作。
6
6
 
7
+ 支持两种数据库模式:
8
+ 1. 项目数据库(默认):位于项目目录下的 config/config.db
9
+ 2. 全局数据库:位于包内的 ../data/config.db
10
+
11
+ 用户可通过在 config.toml 中配置以下选项来选择使用全局数据库:
12
+ ```toml
13
+ [ErisPulse.storage]
14
+ use_global_db = true
15
+ ```
16
+
7
17
  {!--< tips >!--}
8
18
  1. 支持JSON序列化存储复杂数据类型
9
19
  2. 提供事务支持确保数据一致性
@@ -25,6 +35,16 @@ class StorageManager:
25
35
 
26
36
  单例模式实现,提供键值存储的增删改查、事务和快照管理
27
37
 
38
+ 支持两种数据库模式:
39
+ 1. 项目数据库(默认):位于项目目录下的 config/config.db
40
+ 2. 全局数据库:位于包内的 ../data/config.db
41
+
42
+ 用户可通过在 config.toml 中配置以下选项来选择使用全局数据库:
43
+ ```toml
44
+ [ErisPulse.storage]
45
+ use_global_db = true
46
+ ```
47
+
28
48
  {!--< tips >!--}
29
49
  1. 使用get/set方法操作存储项
30
50
  2. 使用transaction上下文管理事务
@@ -33,44 +53,93 @@ class StorageManager:
33
53
  """
34
54
 
35
55
  _instance = None
36
- db_path = os.path.join(os.path.dirname(__file__), "../data/config.db")
37
- SNAPSHOT_DIR = os.path.join(os.path.dirname(__file__), "../data/snapshots")
38
-
56
+ # 默认数据库放在项目下的 config/config.db
57
+ DEFAULT_PROJECT_DB_PATH = os.path.join(os.getcwd(), "config", "config.db")
58
+ # 包内全局数据库路径
59
+ GLOBAL_DB_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "../data/config.db"))
60
+ SNAPSHOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../data/snapshots"))
61
+
39
62
  def __new__(cls, *args, **kwargs):
40
63
  if not cls._instance:
41
64
  cls._instance = super().__new__(cls)
42
65
  return cls._instance
43
66
 
44
67
  def __init__(self):
45
- if not hasattr(self, "_initialized"):
46
- # 确保关键属性在初始化时都有默认值
47
- self._last_snapshot_time = time.time()
48
- self._snapshot_interval = 3600
49
- self._init_db()
50
- self._initialized = True
68
+ # 避免重复初始化
69
+ if hasattr(self, '_initialized') and self._initialized:
70
+ return
71
+
72
+ # 确保目录存在
73
+ self._ensure_directories()
74
+
75
+ # 根据配置决定使用哪个数据库
76
+ from .config import config
77
+ use_global_db = config.getConfig("ErisPulse.storage.use_global_db", False)
78
+
79
+ if use_global_db and os.path.exists(self.GLOBAL_DB_PATH):
80
+ self.db_path = self.GLOBAL_DB_PATH
81
+ else:
82
+ self.db_path = self.DEFAULT_PROJECT_DB_PATH
83
+
84
+ self._last_snapshot_time = time.time()
85
+ self._snapshot_interval = 3600
86
+
87
+ self._init_db()
88
+ self._initialized = True
89
+
90
+ def _ensure_directories(self) -> None:
91
+ """
92
+ 确保必要的目录存在
93
+ """
94
+ # 确保项目数据库目录存在
95
+ try:
96
+ os.makedirs(os.path.dirname(self.DEFAULT_PROJECT_DB_PATH), exist_ok=True)
97
+ except Exception:
98
+ pass # 如果无法创建项目目录,则跳过
99
+
100
+ # 确保快照目录存在
101
+ try:
102
+ os.makedirs(self.SNAPSHOT_DIR, exist_ok=True)
103
+ except Exception:
104
+ pass # 如果无法创建快照目录,则跳过
51
105
 
52
106
  def _init_db(self) -> None:
53
107
  """
54
108
  {!--< internal-use >!--}
55
109
  初始化数据库
56
110
  """
57
- os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
58
- os.makedirs(self.SNAPSHOT_DIR, exist_ok=True)
59
- conn = sqlite3.connect(self.db_path)
60
-
61
- # 启用WAL模式提高并发性能
62
- conn.execute("PRAGMA journal_mode=WAL")
63
- conn.execute("PRAGMA synchronous=NORMAL")
111
+ from .logger import logger
112
+
113
+ logger.debug(f"初始化数据库: {self.db_path}")
114
+ logger.debug(f"创建数据库目录: {os.path.dirname(self.db_path)}")
64
115
 
65
- cursor = conn.cursor()
66
- cursor.execute("""
67
- CREATE TABLE IF NOT EXISTS config (
68
- key TEXT PRIMARY KEY,
69
- value TEXT NOT NULL
70
- )
71
- """)
72
- conn.commit()
73
- conn.close()
116
+ try:
117
+ os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
118
+ except Exception:
119
+ pass # 如果无法创建目录,则继续尝试连接数据库
120
+
121
+ try:
122
+ conn = sqlite3.connect(self.db_path)
123
+
124
+ # 启用WAL模式提高并发性能
125
+ conn.execute("PRAGMA journal_mode=WAL")
126
+ conn.execute("PRAGMA synchronous=NORMAL")
127
+
128
+ cursor = conn.cursor()
129
+ cursor.execute("""
130
+ CREATE TABLE IF NOT EXISTS config (
131
+ key TEXT PRIMARY KEY,
132
+ value TEXT NOT NULL
133
+ )
134
+ """)
135
+ conn.commit()
136
+ conn.close()
137
+ except sqlite3.OperationalError as e:
138
+ logger.error(f"无法创建或打开数据库文件: {e}")
139
+ raise
140
+ except Exception as e:
141
+ logger.error(f"初始化数据库时发生未知错误: {e}")
142
+ raise
74
143
 
75
144
  # 初始化自动快照调度器
76
145
  self._last_snapshot_time = time.time() # 初始化为当前时间
@@ -88,6 +157,10 @@ class StorageManager:
88
157
  >>> timeout = storage.get("network.timeout", 30)
89
158
  >>> user_settings = storage.get("user.settings", {})
90
159
  """
160
+ # 避免在初始化过程中调用此方法导致问题
161
+ if not hasattr(self, '_initialized') or not self._initialized:
162
+ return default
163
+
91
164
  try:
92
165
  with sqlite3.connect(self.db_path) as conn:
93
166
  cursor = conn.cursor()
@@ -104,8 +177,13 @@ class StorageManager:
104
177
  self._init_db()
105
178
  return self.get(key, default)
106
179
  else:
107
- from . import logger
180
+ from .logger import logger
108
181
  logger.error(f"数据库操作错误: {e}")
182
+ return default
183
+ except Exception as e:
184
+ from .logger import logger
185
+ logger.error(f"获取存储项 {key} 时发生错误: {e}")
186
+ return default
109
187
 
110
188
  def get_all_keys(self) -> List[str]:
111
189
  """
@@ -117,11 +195,20 @@ class StorageManager:
117
195
  >>> all_keys = storage.get_all_keys()
118
196
  >>> print(f"共有 {len(all_keys)} 个存储项")
119
197
  """
120
- with sqlite3.connect(self.db_path) as conn:
121
- cursor = conn.cursor()
122
- cursor.execute("SELECT key FROM config")
123
- return [row[0] for row in cursor.fetchall()]
198
+ # 避免在初始化过程中调用此方法导致问题
199
+ if not hasattr(self, '_initialized') or not self._initialized:
200
+ return []
124
201
 
202
+ try:
203
+ with sqlite3.connect(self.db_path) as conn:
204
+ cursor = conn.cursor()
205
+ cursor.execute("SELECT key FROM config")
206
+ return [row[0] for row in cursor.fetchall()]
207
+ except Exception as e:
208
+ from .logger import logger
209
+ logger.error(f"获取所有键名时发生错误: {e}")
210
+ return []
211
+
125
212
  def set(self, key: str, value: Any) -> bool:
126
213
  """
127
214
  设置存储项的值
@@ -134,6 +221,10 @@ class StorageManager:
134
221
  >>> storage.set("app.name", "MyApp")
135
222
  >>> storage.set("user.settings", {"theme": "dark"})
136
223
  """
224
+ # 避免在初始化过程中调用此方法导致问题
225
+ if not hasattr(self, '_initialized') or not self._initialized:
226
+ return False
227
+
137
228
  try:
138
229
  serialized_value = json.dumps(value) if isinstance(value, (dict, list)) else str(value)
139
230
  with self.transaction():
@@ -146,6 +237,8 @@ class StorageManager:
146
237
  self._check_auto_snapshot()
147
238
  return True
148
239
  except Exception as e:
240
+ from .logger import logger
241
+ logger.error(f"设置存储项 {key} 失败: {e}")
149
242
  return False
150
243
 
151
244
  def set_multi(self, items: Dict[str, Any]) -> bool:
@@ -162,6 +255,10 @@ class StorageManager:
162
255
  >>> "app.debug": True
163
256
  >>> })
164
257
  """
258
+ # 避免在初始化过程中调用此方法导致问题
259
+ if not hasattr(self, '_initialized') or not self._initialized:
260
+ return False
261
+
165
262
  try:
166
263
  with self.transaction():
167
264
  conn = sqlite3.connect(self.db_path)
@@ -175,7 +272,7 @@ class StorageManager:
175
272
 
176
273
  self._check_auto_snapshot()
177
274
  return True
178
- except Exception as e:
275
+ except Exception:
179
276
  return False
180
277
 
181
278
  def getConfig(self, key: str, default: Any = None) -> Any:
@@ -188,7 +285,7 @@ class StorageManager:
188
285
  try:
189
286
  from .config import config
190
287
  return config.getConfig(key, default)
191
- except Exception as e:
288
+ except Exception:
192
289
  return default
193
290
 
194
291
  def setConfig(self, key: str, value: Any) -> bool:
@@ -201,7 +298,7 @@ class StorageManager:
201
298
  try:
202
299
  from .config import config
203
300
  return config.setConfig(key, value)
204
- except Exception as e:
301
+ except Exception:
205
302
  return False
206
303
 
207
304
  def delete(self, key: str) -> bool:
@@ -214,6 +311,10 @@ class StorageManager:
214
311
  :example:
215
312
  >>> storage.delete("temp.session")
216
313
  """
314
+ # 避免在初始化过程中调用此方法导致问题
315
+ if not hasattr(self, '_initialized') or not self._initialized:
316
+ return False
317
+
217
318
  try:
218
319
  with self.transaction():
219
320
  conn = sqlite3.connect(self.db_path)
@@ -224,7 +325,7 @@ class StorageManager:
224
325
 
225
326
  self._check_auto_snapshot()
226
327
  return True
227
- except Exception as e:
328
+ except Exception:
228
329
  return False
229
330
 
230
331
  def delete_multi(self, keys: List[str]) -> bool:
@@ -237,6 +338,10 @@ class StorageManager:
237
338
  :example:
238
339
  >>> storage.delete_multi(["temp.key1", "temp.key2"])
239
340
  """
341
+ # 避免在初始化过程中调用此方法导致问题
342
+ if not hasattr(self, '_initialized') or not self._initialized:
343
+ return False
344
+
240
345
  try:
241
346
  with self.transaction():
242
347
  conn = sqlite3.connect(self.db_path)
@@ -247,7 +352,7 @@ class StorageManager:
247
352
 
248
353
  self._check_auto_snapshot()
249
354
  return True
250
- except Exception as e:
355
+ except Exception:
251
356
  return False
252
357
 
253
358
  def get_multi(self, keys: List[str]) -> Dict[str, Any]:
@@ -260,14 +365,23 @@ class StorageManager:
260
365
  :example:
261
366
  >>> settings = storage.get_multi(["app.name", "app.version"])
262
367
  """
263
- conn = sqlite3.connect(self.db_path)
264
- cursor = conn.cursor()
265
- placeholders = ','.join(['?'] * len(keys))
266
- cursor.execute(f"SELECT key, value FROM config WHERE key IN ({placeholders})", keys)
267
- results = {row[0]: json.loads(row[1]) if row[1].startswith(('{', '[')) else row[1]
268
- for row in cursor.fetchall()}
269
- conn.close()
270
- return results
368
+ # 避免在初始化过程中调用此方法导致问题
369
+ if not hasattr(self, '_initialized') or not self._initialized:
370
+ return {}
371
+
372
+ try:
373
+ conn = sqlite3.connect(self.db_path)
374
+ cursor = conn.cursor()
375
+ placeholders = ','.join(['?'] * len(keys))
376
+ cursor.execute(f"SELECT key, value FROM config WHERE key IN ({placeholders})", keys)
377
+ results = {row[0]: json.loads(row[1]) if row[1].startswith(('{', '[')) else row[1]
378
+ for row in cursor.fetchall()}
379
+ conn.close()
380
+ return results
381
+ except Exception as e:
382
+ from .logger import logger
383
+ logger.error(f"批量获取存储项失败: {e}")
384
+ return {}
271
385
 
272
386
  def transaction(self) -> 'StorageManager._Transaction':
273
387
  """
@@ -280,6 +394,16 @@ class StorageManager:
280
394
  >>> storage.set("key1", "value1")
281
395
  >>> storage.set("key2", "value2")
282
396
  """
397
+ # 避免在初始化过程中调用此方法导致问题
398
+ if not hasattr(self, '_initialized') or not self._initialized:
399
+ # 返回一个空的事务对象
400
+ class EmptyTransaction:
401
+ def __enter__(self):
402
+ return self
403
+ def __exit__(self, *args):
404
+ pass
405
+ return EmptyTransaction()
406
+
283
407
  return self._Transaction(self)
284
408
 
285
409
  class _Transaction:
@@ -308,19 +432,29 @@ class StorageManager:
308
432
  """
309
433
  退出事务上下文
310
434
  """
311
- if exc_type is None:
312
- self.conn.commit()
313
- else:
314
- self.conn.rollback()
315
- from .logger import logger
316
- logger.error(f"事务执行失败: {exc_val}")
317
- self.conn.close()
435
+ if self.conn is not None:
436
+ try:
437
+ if exc_type is None:
438
+ if hasattr(self.conn, 'commit'):
439
+ self.conn.commit()
440
+ else:
441
+ if hasattr(self.conn, 'rollback'):
442
+ self.conn.rollback()
443
+ from .logger import logger
444
+ logger.error(f"事务执行失败: {exc_val}")
445
+ finally:
446
+ if hasattr(self.conn, 'close'):
447
+ self.conn.close()
318
448
 
319
449
  def _check_auto_snapshot(self) -> None:
320
450
  """
321
451
  {!--< internal-use >!--}
322
452
  检查并执行自动快照
323
453
  """
454
+ # 避免在初始化过程中调用此方法导致问题
455
+ if not hasattr(self, '_initialized') or not self._initialized:
456
+ return
457
+
324
458
  from .logger import logger
325
459
 
326
460
  if not hasattr(self, '_last_snapshot_time') or self._last_snapshot_time is None:
@@ -358,6 +492,10 @@ class StorageManager:
358
492
  >>> # 每30分钟自动快照
359
493
  >>> storage.set_snapshot_interval(1800)
360
494
  """
495
+ # 避免在初始化过程中调用此方法导致问题
496
+ if not hasattr(self, '_initialized') or not self._initialized:
497
+ return
498
+
361
499
  self._snapshot_interval = seconds
362
500
 
363
501
  def clear(self) -> bool:
@@ -369,6 +507,10 @@ class StorageManager:
369
507
  :example:
370
508
  >>> storage.clear() # 清空所有存储
371
509
  """
510
+ # 避免在初始化过程中调用此方法导致问题
511
+ if not hasattr(self, '_initialized') or not self._initialized:
512
+ return False
513
+
372
514
  try:
373
515
  conn = sqlite3.connect(self.db_path)
374
516
  cursor = conn.cursor()
@@ -376,7 +518,7 @@ class StorageManager:
376
518
  conn.commit()
377
519
  conn.close()
378
520
  return True
379
- except Exception as e:
521
+ except Exception:
380
522
  return False
381
523
 
382
524
  def __getattr__(self, key: str) -> Any:
@@ -386,16 +528,23 @@ class StorageManager:
386
528
  :param key: 存储项键名
387
529
  :return: 存储项的值
388
530
 
389
- :raises KeyError: 当存储项不存在时抛出
531
+ :raises AttributeError: 当存储项不存在时抛出
390
532
 
391
533
  :example:
392
534
  >>> app_name = storage.app_name
393
535
  """
536
+ # 避免访问内置属性时出现问题
537
+ if key.startswith('_'):
538
+ raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{key}'")
539
+
540
+ # 避免在初始化过程中调用此方法导致问题
541
+ if not hasattr(self, '_initialized') or not self._initialized:
542
+ raise AttributeError(f"存储尚未初始化完成: {key}")
543
+
394
544
  try:
395
545
  return self.get(key)
396
- except KeyError:
397
- from . import logger
398
- logger.error(f"存储项 {key} 不存在")
546
+ except Exception:
547
+ raise AttributeError(f"存储项 {key} 不存在或访问出错")
399
548
 
400
549
  def __setattr__(self, key: str, value: Any) -> None:
401
550
  """
@@ -407,10 +556,20 @@ class StorageManager:
407
556
  :example:
408
557
  >>> storage.app_name = "MyApp"
409
558
  """
559
+ # 避免在初始化过程中出现问题
560
+ if key.startswith('_'):
561
+ super().__setattr__(key, value)
562
+ return
563
+
564
+ # 如果还未初始化完成,直接设置属性
565
+ if not hasattr(self, '_initialized') or not self._initialized:
566
+ super().__setattr__(key, value)
567
+ return
568
+
410
569
  try:
411
570
  self.set(key, value)
412
571
  except Exception as e:
413
- from . import logger
572
+ from .logger import logger
414
573
  logger.error(f"设置存储项 {key} 失败: {e}")
415
574
 
416
575
  def snapshot(self, name: Optional[str] = None) -> str:
@@ -426,6 +585,10 @@ class StorageManager:
426
585
  >>> # 创建时间戳快照
427
586
  >>> snapshot_path = storage.snapshot()
428
587
  """
588
+ # 避免在初始化过程中调用此方法导致问题
589
+ if not hasattr(self, '_initialized') or not self._initialized:
590
+ raise RuntimeError("存储尚未初始化完成")
591
+
429
592
  if not name:
430
593
  name = datetime.now().strftime("%Y%m%d_%H%M%S")
431
594
  snapshot_path = os.path.join(self.SNAPSHOT_DIR, f"{name}.db")
@@ -439,16 +602,16 @@ class StorageManager:
439
602
  try:
440
603
  self._conn.close()
441
604
  except Exception as e:
442
- from . import logger
605
+ from .logger import logger
443
606
  logger.warning(f"关闭数据库连接时出错: {e}")
444
607
 
445
608
  # 创建快照
446
609
  shutil.copy2(self.db_path, snapshot_path)
447
- from . import logger
610
+ from .logger import logger
448
611
  logger.info(f"数据库快照已创建: {snapshot_path}")
449
612
  return snapshot_path
450
613
  except Exception as e:
451
- from . import logger
614
+ from .logger import logger
452
615
  logger.error(f"创建快照失败: {e}")
453
616
  raise
454
617
 
@@ -462,11 +625,15 @@ class StorageManager:
462
625
  :example:
463
626
  >>> storage.restore("before_update")
464
627
  """
628
+ # 避免在初始化过程中调用此方法导致问题
629
+ if not hasattr(self, '_initialized') or not self._initialized:
630
+ return False
631
+
465
632
  snapshot_path = os.path.join(self.SNAPSHOT_DIR, f"{snapshot_name}.db") \
466
633
  if not snapshot_name.endswith('.db') else snapshot_name
467
634
 
468
635
  if not os.path.exists(snapshot_path):
469
- from . import logger
636
+ from .logger import logger
470
637
  logger.error(f"快照文件不存在: {snapshot_path}")
471
638
  return False
472
639
 
@@ -476,17 +643,17 @@ class StorageManager:
476
643
  try:
477
644
  self._conn.close()
478
645
  except Exception as e:
479
- from . import logger
646
+ from .logger import logger
480
647
  logger.warning(f"关闭数据库连接时出错: {e}")
481
648
 
482
649
  # 执行恢复操作
483
650
  shutil.copy2(snapshot_path, self.db_path)
484
651
  self._init_db() # 恢复后重新初始化数据库连接
485
- from . import logger
652
+ from .logger import logger
486
653
  logger.info(f"数据库已从快照恢复: {snapshot_path}")
487
654
  return True
488
655
  except Exception as e:
489
- from . import logger
656
+ from .logger import logger
490
657
  logger.error(f"恢复快照失败: {e}")
491
658
  return False
492
659
 
@@ -500,17 +667,26 @@ class StorageManager:
500
667
  >>> for name, date, size in storage.list_snapshots():
501
668
  >>> print(f"{name} - {date} ({size} bytes)")
502
669
  """
503
- snapshots = []
504
- for f in os.listdir(self.SNAPSHOT_DIR):
505
- if f.endswith('.db'):
506
- path = os.path.join(self.SNAPSHOT_DIR, f)
507
- stat = os.stat(path)
508
- snapshots.append((
509
- f[:-3], # 去掉.db后缀
510
- datetime.fromtimestamp(stat.st_ctime),
511
- stat.st_size
512
- ))
513
- return sorted(snapshots, key=lambda x: x[1], reverse=True)
670
+ # 避免在初始化过程中调用此方法导致问题
671
+ if not hasattr(self, '_initialized') or not self._initialized:
672
+ return []
673
+
674
+ try:
675
+ snapshots = []
676
+ for f in os.listdir(self.SNAPSHOT_DIR):
677
+ if f.endswith('.db'):
678
+ path = os.path.join(self.SNAPSHOT_DIR, f)
679
+ stat = os.stat(path)
680
+ snapshots.append((
681
+ f[:-3], # 去掉.db后缀
682
+ datetime.fromtimestamp(stat.st_ctime),
683
+ stat.st_size
684
+ ))
685
+ return sorted(snapshots, key=lambda x: x[1], reverse=True)
686
+ except Exception as e:
687
+ from .logger import logger
688
+ logger.error(f"列出快照时发生错误: {e}")
689
+ return []
514
690
 
515
691
  def delete_snapshot(self, snapshot_name: str) -> bool:
516
692
  """
@@ -522,21 +698,25 @@ class StorageManager:
522
698
  :example:
523
699
  >>> storage.delete_snapshot("old_backup")
524
700
  """
701
+ # 避免在初始化过程中调用此方法导致问题
702
+ if not hasattr(self, '_initialized') or not self._initialized:
703
+ return False
704
+
525
705
  snapshot_path = os.path.join(self.SNAPSHOT_DIR, f"{snapshot_name}.db") \
526
706
  if not snapshot_name.endswith('.db') else snapshot_name
527
707
 
528
708
  if not os.path.exists(snapshot_path):
529
- from . import logger
709
+ from .logger import logger
530
710
  logger.error(f"快照文件不存在: {snapshot_path}")
531
711
  return False
532
712
 
533
713
  try:
534
714
  os.remove(snapshot_path)
535
- from . import logger
715
+ from .logger import logger
536
716
  logger.info(f"快照已删除: {snapshot_path}")
537
717
  return True
538
718
  except Exception as e:
539
- from . import logger
719
+ from .logger import logger
540
720
  logger.error(f"删除快照失败: {e}")
541
721
  return False
542
722
 
@@ -545,3 +725,4 @@ storage = StorageManager()
545
725
  __all__ = [
546
726
  "storage"
547
727
  ]
728
+