Spaces:
Runtime error
Runtime error
| """ | |
| Data Manager Module | |
| Handles in-memory storage, persistence, and data operations. | |
| """ | |
| import json | |
| import logging | |
| from typing import List, Dict, Any, Set | |
| from datetime import datetime | |
| from pathlib import Path | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| DATA_DIR = Path("data") | |
| LISTINGS_FILE = DATA_DIR / "listings.json" | |
| FAVORITES_FILE = DATA_DIR / "favorites.json" | |
| class DataManager: | |
| """Manages in-memory and persistent storage of listings.""" | |
| def __init__(self): | |
| self.listings: Dict[str, Dict[str, Any]] = {} | |
| self.favorites: Set[str] = set() | |
| self.seen_ids: Set[str] = set() | |
| self._ensure_data_dir() | |
| self._load_data() | |
| def _ensure_data_dir(self): | |
| """Ensure data directory exists.""" | |
| DATA_DIR.mkdir(exist_ok=True) | |
| def _load_data(self): | |
| """Load persisted data from files.""" | |
| try: | |
| if LISTINGS_FILE.exists(): | |
| with open(LISTINGS_FILE, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| self.listings = data.get("listings", {}) | |
| self.seen_ids = set(self.listings.keys()) | |
| logger.info(f"Loaded {len(self.listings)} listings from disk") | |
| except Exception as e: | |
| logger.error(f"Error loading listings: {e}") | |
| try: | |
| if FAVORITES_FILE.exists(): | |
| with open(FAVORITES_FILE, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| self.favorites = set(data.get("favorites", [])) | |
| logger.info(f"Loaded {len(self.favorites)} favorites from disk") | |
| except Exception as e: | |
| logger.error(f"Error loading favorites: {e}") | |
| def _save_listings(self): | |
| """Persist listings to disk.""" | |
| try: | |
| with open(LISTINGS_FILE, "w", encoding="utf-8") as f: | |
| json.dump({"listings": self.listings}, f, ensure_ascii=False, indent=2) | |
| except Exception as e: | |
| logger.error(f"Error saving listings: {e}") | |
| def _save_favorites(self): | |
| """Persist favorites to disk.""" | |
| try: | |
| with open(FAVORITES_FILE, "w", encoding="utf-8") as f: | |
| json.dump({"favorites": list(self.favorites)}, f, ensure_ascii=False, indent=2) | |
| except Exception as e: | |
| logger.error(f"Error saving favorites: {e}") | |
| def add_listings(self, listings: List[Dict[str, Any]]) -> int: | |
| """ | |
| Add new listings to storage. | |
| Args: | |
| listings: List of listing dictionaries | |
| Returns: | |
| Number of new listings added | |
| """ | |
| new_count = 0 | |
| for listing in listings: | |
| divar_id = listing.get("divar_id") | |
| if divar_id and divar_id not in self.seen_ids: | |
| self.listings[divar_id] = listing | |
| self.seen_ids.add(divar_id) | |
| new_count += 1 | |
| if new_count > 0: | |
| self._save_listings() | |
| logger.info(f"Added {new_count} new listings") | |
| return new_count | |
| def get_all_listings(self) -> List[Dict[str, Any]]: | |
| """Get all listings.""" | |
| return list(self.listings.values()) | |
| def get_listings_by_neighborhood(self, neighborhood: str) -> List[Dict[str, Any]]: | |
| """Get listings for a specific neighborhood.""" | |
| return [l for l in self.listings.values() if l.get("neighborhood") == neighborhood] | |
| def get_budget_fit_listings(self) -> List[Dict[str, Any]]: | |
| """Get listings that fit the budget.""" | |
| return [l for l in self.listings.values() if l.get("budget_fit") == "fits_budget"] | |
| def get_listing(self, divar_id: str) -> Dict[str, Any]: | |
| """Get a specific listing by ID.""" | |
| return self.listings.get(divar_id, {}) | |
| def add_favorite(self, divar_id: str) -> bool: | |
| """Add a listing to favorites (max 3).""" | |
| if len(self.favorites) >= 3 and divar_id not in self.favorites: | |
| logger.warning("Favorites limit (3) reached") | |
| return False | |
| self.favorites.add(divar_id) | |
| self._save_favorites() | |
| logger.info(f"Added {divar_id} to favorites") | |
| return True | |
| def remove_favorite(self, divar_id: str) -> bool: | |
| """Remove a listing from favorites.""" | |
| if divar_id in self.favorites: | |
| self.favorites.remove(divar_id) | |
| self._save_favorites() | |
| logger.info(f"Removed {divar_id} from favorites") | |
| return True | |
| return False | |
| def get_favorites(self) -> List[Dict[str, Any]]: | |
| """Get all favorite listings.""" | |
| return [self.listings[fid] for fid in self.favorites if fid in self.listings] | |
| def is_favorite(self, divar_id: str) -> bool: | |
| """Check if a listing is in favorites.""" | |
| return divar_id in self.favorites | |
| def clear_all(self): | |
| """Clear all data (for testing).""" | |
| self.listings.clear() | |
| self.favorites.clear() | |
| self.seen_ids.clear() | |
| self._save_listings() | |
| self._save_favorites() | |
| logger.info("Cleared all data") | |
| def get_statistics(self) -> Dict[str, Any]: | |
| """Get statistics about stored listings.""" | |
| listings = self.get_all_listings() | |
| budget_fit = len(self.get_budget_fit_listings()) | |
| return { | |
| "total_listings": len(listings), | |
| "budget_fit_count": budget_fit, | |
| "favorites_count": len(self.favorites), | |
| "neighborhoods": list(set(l.get("neighborhood", "") for l in listings)), | |
| "last_updated": datetime.now().isoformat() | |
| } | |
| # Global instance | |
| _data_manager = None | |
| def get_data_manager() -> DataManager: | |
| """Factory function to get or create data manager instance.""" | |
| global _data_manager | |
| if _data_manager is None: | |
| _data_manager = DataManager() | |
| return _data_manager | |
| if __name__ == "__main__": | |
| manager = get_data_manager() | |
| print(f"Statistics: {manager.get_statistics()}") | |