Coverage for src/local_deep_research/library/download_management/filters/resource_filter.py: 100%
25 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-03 23:15 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-03 23:15 +0000
1"""
2Resource Filter
4Smart filtering logic for downloadable resources based on failure history,
5cooldowns, and retry policies. Replaces simple file existence checks with
6intelligent retry management.
7"""
9from typing import List, Optional
11from loguru import logger
13from ..retry_manager import RetryManager, ResourceFilterResult, FilterSummary
16class ResourceFilter:
17 """Filter resources for download based on history and policies"""
19 def __init__(self, username: str, password: Optional[str] = None):
20 """
21 Initialize the resource filter.
23 Args:
24 username: Username for database access
25 password: Optional password for encrypted database
26 """
27 self.username = username
28 self.retry_manager = RetryManager(username, password)
29 logger.info(f"Initialized for user: {username}")
31 def filter_downloadable_resources(
32 self, resources: List
33 ) -> List[ResourceFilterResult]:
34 """
35 Filter resources that are available for download.
37 Args:
38 resources: List of ResearchResource objects to filter
40 Returns:
41 List of ResourceFilterResult objects with retry decisions
42 """
43 logger.info(f"Filtering {len(resources)} resources")
45 # Use retry manager to filter based on failure history
46 return self.retry_manager.filter_resources(resources)
48 def get_filter_summary(self, resources: List) -> FilterSummary:
49 """
50 Get a summary of filtering results.
52 Args:
53 resources: List of resources that were filtered
55 Returns:
56 FilterSummary object with detailed counts
57 """
58 results = self.filter_downloadable_resources(resources)
59 return self.retry_manager.get_filter_summary(results)
61 def get_skipped_resources_info(self, resources: List) -> dict:
62 """
63 Get detailed information about skipped resources for UI display.
65 Args:
66 resources: List of all resources
68 Returns:
69 Dictionary with detailed skip information
70 """
71 results = self.filter_downloadable_resources(resources)
73 skipped_resources = []
74 for result in results:
75 if not result.can_retry:
76 status_info = (
77 self.retry_manager.status_tracker.get_resource_status(
78 result.resource_id
79 )
80 )
81 skipped_resources.append(
82 {
83 "resource_id": result.resource_id,
84 "status": result.status,
85 "reason": result.reason,
86 "estimated_wait_minutes": result.estimated_wait.total_seconds()
87 // 60
88 if result.estimated_wait
89 else None,
90 "status_info": status_info,
91 }
92 )
94 return {
95 "total_skipped": len(skipped_resources),
96 "permanently_failed": [
97 r
98 for r in skipped_resources
99 if r["status"] == "permanently_failed"
100 ],
101 "temporarily_failed": [
102 r
103 for r in skipped_resources
104 if r["status"] == "temporarily_failed"
105 ],
106 "other_skipped": [
107 r
108 for r in skipped_resources
109 if r["status"]
110 not in ["permanently_failed", "temporarily_failed"]
111 ],
112 "skipped_resources": skipped_resources,
113 }
115 def should_skip_resource(self, resource_id: int) -> tuple[bool, str]:
116 """
117 Quick check if a specific resource should be skipped.
119 Args:
120 resource_id: Resource identifier
122 Returns:
123 Tuple of (should_skip, reason)
124 """
125 decision = self.retry_manager.should_retry_resource(resource_id)
126 return (
127 not decision.can_retry,
128 decision.reason or "Resource not available for retry",
129 )