Skip to content

Latest commit

 

History

History

README.md

tabun_stat

Считалка статистики для Табуна. На вход (который нужно написать самостоятельно) принимает пользователей, блоги, посты и комменты, а на выходе даёт пачку файлов (в основном csv) с разными интересными числами и иногда словами.

Посты на Табуне:

Установка и использование

Стандартно, скачав и запустив в каталоге tabun_stat (рекомендуется предварительно создать и активировать виртуальное окружение):

pip install -e .

После этого появятся команды tabun_stat и tabun_stat_graph.

Для работы требуется конфиг; по умолчанию есть config.toml. Укажите конфиг при запуске tabun_stat:

tabun_stat -vv -c config.toml

Опция -vv включает подробный вывод с прогресс-барами.

Для работы tabun_stat требуется какой-то источник данных. Подразумевается, что он у вас есть и вы его можете подключить самостоятельно. В репозитории лежит демонстрационный пример данных для sqlite3 базы данных; чтобы воспользоваться им, создайте базу из прилагаемого sql-дампа:

$ sqlite3 demo.sqlite3 < demo.sql

Создайте конфиг для этого источника в файле datasource.toml:

name = ":sqlite3.Sqlite3DataSource"
path = "demo.sqlite3"

(двоеточие в начале name — сокращение для поиска модуля внутри пакета tabun_stat.datasource)

и подключите этот файл в основном конфиге (в стандартном файле config.toml уже прописано по умолчанию):

datasource_file = "datasource.toml"

Как создать свой источник данных

Источник данных — это класс-потомок tabun_stat.datasource.BaseDataSource. Чтобы создать свой источник, унаследуйтесь от него, реализуйте все абстрактные методы:

from tabun_stat.datasource import BaseDataSource
from tabun_stat.stat import TabunStat

class CustomDataSource(BaseDataSource):
    def __init__(self, *, option1: str, option2: int):
        self.option1 = option1
        self.option2 = option2
        # и так далее по вкусу

    def start(self, stat: TabunStat) -> None:
        pass  # по вкусу

    def destroy(self) -> None:
        pass  # по вкусу

    # и так далее

и включите его использование в конфиге (datasource.toml):

name = "ваш_модуль.CustomDataSource"
option1 = "значение опции 1"
option2 = 777

Все ключи из конфига, кроме name, передаются в __init__ как аргументы.

Кратко о том, какие абстрактные методы нужно переопределить:

  • get_user_by_id — получение одного пользователя;

  • get_users_limits — получение статистики по пользователям;

  • get_blog_by_id — получение одного блога;

  • get_blogs_limits — получение базовой статистики по блогам;

  • get_post_by_id — получение одного поста;

  • get_posts_limits — получение базовой статистики по постам;

  • get_comment_by_id — получение одного коммента;

  • get_comments_limits — получение базовой статистики по комментам.

Для источников на базе популярных СУБД почти всё это сводится к несложным SQL-запросам.

Также есть ещё методы, имеющие реализацию по умолчанию, но крайне неэффективную (в сотни раз медленнее эффективных реализаций на SQL), поэтому их тоже крайне желательно переопределить:

  • get_blog_statuses_by_ids и get_blog_ids_of_posts — для этих методов можно применить какое-нибудь кэширование;

  • iter_users — получение пользователей пачками;

  • iter_blogs — получение блогов пачками;

  • iter_posts — получение постов пачками;

  • iter_comments — получение комментов пачками.

iter-методы — это генераторы, которые выдают запрашиваемые объекты через yield. Если указаны фильтры, то должны применяться прописанные в них ограничения. Сортировка возвращаемых значений не определена. В целях оптимизации yield'ятся не отдельно объекты по одному, а списки объектов. (В стандартной неэффективной реализации этот список состоит из одного элемента, а лучше бы сотни.)

Есть ещё несколько методов, стандартная реализация которых достаточно эффективна, но иногда может быть полезно переопределить и их тоже (например, чтобы прикрутить кэширование):

  • get_username_by_user_id — получить имя пользователя по его id;

  • get_blog_status_by_id — статус блога по его id;

  • get_blog_id_of_post — получение блога поста.

Подробнее о том, как это всё реализовывать, читайте в docstring'ах в файле tabun_stat/processors/base.py. И вообще, код — лучшая документация, читайте пример для sqlite3 ;)

Как создать свой обработчик

Обработчик — это класс-потомок tabun_stat.processors.BaseProcessor. Чтобы создать свой источник, унаследуйтесь от него и реализуйте нужные вам методы на свой вкус.

Каждый обработчик считает полную статистику ровно один раз, после чего уничтожается. Использование одного и того же обработчика для подсчёта полной статистики несколько раз не предусмотрено.

Жизненный цикл обработчика (какие методы вызываются):

  • сперва все обработчики создаются;

  • start;

  • begin_users;

  • process_user вызывается столько раз, сколько есть пользователей (сортировка пользователей не определена);

  • end_users;

  • begin_blogs;

  • process_blog вызывается столько раз, сколько есть блогов (сортировка блогов не определена);

  • end_blogs;

  • begin_messages;

  • process_post и process_comment — вызываются гарантированно с сортировкой постов и комментов по времени, что позволяет сделать некоторые оптимизации;

  • end_messages;

  • stop;

  • после всего этого обработчики уничтожаются.

Во все методы передаётся stat — объект TabunStat, через который вы можете получить доступ к источнику данных (stat.source), каталогу для вывода (self.destination) и функции для записи лога (stat.log).

Не забывайте про super:

from datetime import datetime

from tabun_stat import types
from tabun_stat.processors import BaseProcessor
from tabun_stat.stat import TabunStat

class CustomProcessor(BaseProcessor):
    def __init__(self, *, option1: str, option2: int):
        super().__init__()

        self.option1 = option1
        self.option2 = option2
        # и так далее по вкусу

    def start(self, stat: TabunStat) -> None:
        super().start(stat)
        # что-то там

    def process_user(self, stat: TabunStat, user: types.User) -> None:
        ... # что-то там

    def stop(self, stat: TabunStat) -> None:
        # что-то там

        with (stat.destination / "custom.csv").open("w", encoding="utf-8") as fp:
            fp.write("Я сделяль статистику\n")

        super().stop(stat)

    # и так далее

Включается в конфиге (config.toml) аналогично источнику. Обратите внимание, что processors это массив, и поэтому в синтаксисе TOML используются две пары квадратных скобок:

[[processors]]
name = "custom_module.CustomProcessor"
option1 = "hello"
option2 = 4

[[processors]]
name = ":registrations.RegistrationsProcessor"
# ...и другие стандартные обработчики по желанию

Все ключи из конфига, кроме name, передаются в __init__ как аргументы.

Графики

В комплекте также присутствует рисовалка графиков из csv-файлов, сделанная на основе библиотеки svg.charts. По умолчанию она не установлена, доустановите зависимости перед запуском:

pip install -e ".[graph]"

Рисовалке нужен конфиг, содержащий информацию об источнике данных, каталоге для сохранения готовых графиков и параметров рисования. Есть стандартный конфиг graph_config.toml, читающий csv-файлы из каталога stat и сохраняющий графики в папку graphs. Запускается вот так:

tabun_stat_graph -c graph_config.toml

Подробнее о параметрах рисования можно почитать в документации к функции render_plot в файле tabun_stat/graph/renderers.py.