Библиотека monokeys
Клиент одним файлом, без зависимостей. Ставить не обязательно: ключ работает и обычной ссылкой.
Поставить
pip install monokeys
Или тем же файлом, без установки: curl https://monoblock.casa/keys/sdk/python > monokeys.py
Ключ доступа
Ключ выдаёт владелец сервиса. Он бессрочный и без счётчика: сколько запросов сделать — ваше дело, никто их не считает. Единственное, что может случиться, — владелец отзовёт конкретный ключ, если тот начнёт вредить. Без ключа всё тоже работает, но как проба.
# .env KEYS_API_KEY=kx_…
Три способа позвать
from monokeys import Keys
k = Keys()
k.alive("@durov") # весь ответ: объект с полями
k.alive.members_count("@durov") # только одно поле, уже числом
k.alive.text("@durov") # строка для человекаАргументы подключения
| аргумент | по умолчанию | что делает |
|---|---|---|
token | KEYS_API_KEY, иначе публичный | ключ доступа; передаётся только заголовком |
base | адрес, откуда скачан клиент | адрес сервера |
timeout | 20.0 | сколько ждать ответа, секунд |
retries | 1 | повторов при обрыве связи (отказ сервера не повторяется) |
user_agent | monokeys/<версия> | как представляться серверу |
k = Keys(token="kx_…", base="https://monoblock.casa/keys", timeout=5, retries=2)
Аргументы вызова
| аргумент | по умолчанию | что делает |
|---|---|---|
value | — | главное значение: ссылка для alive, вопрос для answer |
only | "" | вернуть только эти поля; несколько — через запятую |
fmt | "json" | json — поля, text — строка для человека, bool — да/нет |
timeout | как у клиента | переопределить ожидание для одного вызова |
**params | — | остальные параметры ключа по именам |
k.alive("@durov", only="members_count") # 11005185
k.alive("@durov", fmt="bool") # 'true'
k.alive("@durov", timeout=3) # не ждать дольше трёх секундАргументы отдельных ключей
| ключ | аргумент | что делает |
|---|---|---|
answer | sources | какие источники спрашивать; несколько — через запятую, пусто — ключ выберет сам |
answer | lang | язык источника: ru или en |
crypto | vs | в каких валютах показать цену, через запятую |
time | to | второе место: во сколько это будет там |
time | at | час по первому месту; пусто — прямо сейчас |
weather | when | сегодня, завтра, послезавтра или число дней вперёд |
weather | days | сколько дней прогноза вернуть, от 1 до 7 |
weather | units | c — Цельсий, f — Фаренгейт |
read | limit | обрезать текст до стольких знаков; пусто — весь |
k.answer('Хайфа', sources='osm,wikidata') # оба ответа, а не один
k.crypto('bitcoin', vs='usd,ils')
k.time('Хайфа', to='Нью-Йорк', at='15:00') # созвон в три — во сколько у них
k.weather('Берлин', when='завтра') # и надо ли брать зонт
k.read('https://peps.python.org/pep-0008/').text # статья без разметки
k.url('bit.ly/3xYz').url # куда ведёт на самом деле
k.alive('@durov', only='title,members_count') # несколько полей сразуКлючи можно исполнять у себя
Ключ — это код, а не услуга. Тот же самый код лежит в пакете: запрос уйдёт к источнику с вашей машины, нас в цепочке не будет. Быстрее, приватнее и не ломается, когда ломаемся мы.
from monokeys import Local
k = Local() # нашего сервера в цепочке нет
k.weather('Берлин').description # 'пасмурно'
k.read('https://example.com/x').text| вызов | что делает |
|---|---|
Local() | все ключи, исполняемые здесь; ни адреса, ни ключа доступа |
AsyncLocal() | то же самое через await, для асинхронного кода |
k.names() | какие ключи есть |
k.describe(имя) | манифест ключа целиком |
Работает без сети
Таймеры считаются у вас: обычный файл sqlite рядом с ботом. Ни ключа, ни запросов, ни ограничений — и наша доступность не становится правильностью вашего бота.
from monokeys import Timers
t = Timers('bans.db') # свой файл, без сети и ключа
t.set(f'unmute:{chat}:{user}', '30m', note='флуд')
async for сработал in t.stream(): # ждёт само
await bot.restrict_chat_member(...)| вызов | что делает |
|---|---|
Timers(path) | хранилище таймеров в файле sqlite; сети и ключа не нужно |
t.set(id, when, note) | поставить; тот же id переставляет, а не задваивает |
t.due() | что созрело; отдаётся один раз |
t.peek() | то же, но не забирая |
t.pending() | кто ещё ждёт и сколько ему осталось |
t.cancel(id) | снять досрочно |
t.stream() | async for: ждёт само, цикл опроса писать не нужно |
t.wait(id) | дождаться одного конкретного |
Что можно спросить у клиента
| вызов | что вернёт |
|---|---|
k.names() | имена всех доступных ключей |
k.fields("alive") | какие поля возвращает ключ |
k.alive.fields() | то же самое, короче |
k.catalog(refresh=True) | полный каталог с описаниями, спросить заново |
k.call("alive", "@durov") | позвать ключ, имя которого известно только в рантайме |
Ответ
Ответ — это словарь, который умеет отвечать и как объект. Опечатка в имени поля не молчит, а показывает список настоящих полей.
res = k.alive("@durov")
res.title == res["title"] # одно и то же
bool(res) # True, если ключ ответил утвердительноОшибки
| исключение | когда |
|---|---|
AccessDenied | ключ неизвестен, отозван или отправлен не по HTTPS |
Unavailable | сервер занят или источник не ответил — осмысленно повторить |
KeysError | всё остальное: нет такого ключа, мусор на входе |
У всех есть .status и .body. Первые две — потомки KeysError, ловятся одним except.
Методы не зашиты в клиент
Список ключей и их полей приходит с сервера, поэтому новый ключ доступен сразу, без обновления пакета.