# built-in from collections import defaultdict from datetime import date, timedelta from itertools import zip_longest from typing import Any, DefaultDict, Dict, Iterator, List, Sequence # external import attr # app from ..networking import requests_session RECENT_URL = 'https://pypistats.org/api/packages/{}/recent' CATEGORIES_URLS = dict( pythons='https://pypistats.org/api/packages/{}/python_minor', systems='https://pypistats.org/api/packages/{}/system', ) @attr.s() class DateList: start = attr.ib(type=date) end = attr.ib(type=date) _data = attr.ib(factory=dict, repr=False, type=Dict[str, int]) def add(self, date: str, value: int): self._data[date] = value def __iter__(self) -> Iterator[int]: moment = self.start while moment <= self.end: yield self._data.get(str(moment), 0) moment += timedelta(1) def make_chart(values: Sequence[int], group: int = None, ticks: str = '_▁▂▃▄▅▆▇█') -> str: peek = max(values) if peek == 0: chart = ticks[-1] * len(values) else: chart = '' for value in values: index = round((len(ticks) - 1) * value / peek) chart += ticks[int(index)] if group: chunks = map(''.join, zip_longest(*[iter(chart)] * group, fillvalue=' ')) chart = ' '.join(chunks).strip() return chart def get_total_downloads(name: str) -> Dict[str, int]: url = RECENT_URL.format(name) with requests_session() as session: response = session.get(url) response.raise_for_status() body = response.json()['data'] return dict( day=body['last_day'], week=body['last_week'], month=body['last_month'], ) def get_downloads_by_category(*, category: str, name: str) -> List[Dict[str, Any]]: url = CATEGORIES_URLS[category].format(name) with requests_session() as session: response = session.get(url) response.raise_for_status() body = response.json()['data'] yesterday = date.today() - timedelta(1) grouped: DefaultDict[str, DateList] grouped = defaultdict(lambda: DateList(start=yesterday - timedelta(30), end=yesterday)) for line in body: category = line['category'].replace('.', '') grouped[category].add(date=line['date'], value=line['downloads']) result = [] for category, dates in grouped.items(): downloads = list(dates) if sum(downloads) == 0: continue result.append(dict( category=category, day=downloads[-1], week=sum(downloads[-7:]), month=sum(downloads), chart=make_chart(downloads[-28:], group=7), )) return result