from collections import defaultdict from dataclasses import dataclass, field from datetime import datetime from operator import itemgetter from typing import Any, Dict, List from stats_model import StatsModel @dataclass(kw_only=True) class BuildDeepStatsModel(StatsModel): """Stats model built around calculating stats for original post notes, with additional data dimensions.""" operation: str = 'build_deep_stats' # Note count by interaction month and year for original posts. notes_by_interaction_month_and_year: Dict[str, Any] = field(init=False) # Top blogs by original post note count. top_interactors: List[Dict[str, Any]] = field(init=False) def __post_init__(self): super().__post_init__() self.notes_by_interaction_month_and_year = self.calculate_notes_by_interaction_month_and_year() self.top_interactors = self.calculate_top_interactors() def calculate_notes_by_interaction_month_and_year(self) -> Dict[str, Any]: # https://docs.python.org/3/library/collections.html#defaultdict-objects date_map: Dict[str, Any] = {} date_map = defaultdict(lambda: {'note_count': 0}, date_map) # Gathering the results. for post_key in self.original_post_map: post = self.original_post_map[post_key] if 'notes' not in post: continue notes = post['notes'] for note in notes: note_date_key = datetime.fromtimestamp(note['timestamp']).strftime('%Y-%m-%d') sts = date_map[note_date_key] sts['date'] = note_date_key if note['type'] != 'posted': sts['note_count'] += 1 return date_map def calculate_top_interactors(self) -> List[Dict[str, Any]]: top_interactors: defaultdict[str, Dict[str, Any]] = defaultdict(lambda: {'note_count': 0}, {}) # Gathering the results. for post_key in self.original_post_map: post = self.original_post_map[post_key] if 'notes' not in post: continue notes = post['notes'] for note in notes: person_key = note['blog_name'] sts = top_interactors[person_key] if 'blog_name' not in sts: sts['blog_name'] = person_key if 'url' not in sts: sts['url'] = f"https://{person_key}.tumblr.com" if note['type'] != 'posted': sts['note_count'] += 1 # https://stackoverflow.com/a/73050 return sorted(top_interactors.values(), key=itemgetter('note_count'), reverse=True)