monokeys
Клиент «Ключей» — маленьких умных функций, которые зовутся одним вызовом. Внутри только стандартная библиотека: зависимостей нет, один файл.
pip install monokeys
from monokeys import Keys
k = Keys() # настраивать нечего
print(k.alive.text("@durov"))
# жив · channel · Pavel Durov · 10 998 851 subscribers
print(k.answer.text("погода в Хайфе"))
# Хайфе: 28.9°C, ветер 2.6 м/с, влажность 58% · источник: weather
Ни регистрации, ни ключа доступа, ни лимита: клиент сам берёт публичный ключ, а он бессрочный и без счётчика.
alive — жив ли канал Telegram
Без аккаунта, без Bot API, без токена: читается публичная превью-страница
t.me, та самая, по которой мессенджеры рисуют картинку ссылки.
k.alive("@durov") # весь ответ объектом
k.alive.members_count("@durov") # 11005185 — только число, уже числом
k.alive.kind("ru_python") # group
k.alive.verified("@BotFather") # True
Понимает любую форму ссылки: @durov, t.me/durov, t.me/durov/123,
t.me/s/durov, t.me/+AbCdEf…, t.me/joinchat/…, DUROV.
Поля ответа: is_alive, kind (channel / group / bot / user), title,
description, members_count, members_label, online_count, verified,
is_private, needs_request, restricted, has_preview, avatar_url,
deep_link, action, username, url, error.
Тонкость, из-за которой наивная проверка врёт: на удалённый канал Telegram
отвечает 200 и рисует заглушку. Живой от мёртвого отличается разметкой, а не
кодом ответа.
answer — ответ из многих источников разом
k.answer.text("кто такой Павел Дуров")
# Па́вел Вале́рьевич Ду́ров — российский и эмиратский предприниматель… · источник: wiki
k.answer.text("погода в Хайфе") # Хайфе: 28.9°C, ветер 2.6 м/с · источник: weather
k.answer.text("курс доллара к шекелю") # 1 USD = 2.9728 ILS (ЕЦБ) · источник: rates
k.answer("Хайфа", sources="osm,wiki") # только карта и Википедия
Вопрос уходит сразу в несколько мест, каждое отвечает своим полем, отдельно
называется лучший ответ и ссылки для проверки. Если sources не указать, ключ
смотрит на вопрос и выбирает сам: про город — карту, про валюту — курсы, про
пакет — реестры пакетов; общая справка спрашивается всегда.
Тринадцать источников, ни одного платного ключа: Википедия, Викиданные, Викисловарь, DuckDuckGo, OpenStreetMap, Open-Meteo, курсы валют, Crossref, arXiv, Open Library, PyPI, npm, GitHub.
Чего тут нет намеренно: моделей — все бесплатные упираются в лимит, а их ответ нечем проверить; и выдачи поисковиков — её нельзя брать по их правилам, а IP у сервера один на все продукты.
Спросить именно тот источник, который нужен
Каждый источник — отдельный метод. Одно и то же слово, разные ответы:
k.answer.weather("Хайфа") # Хайфа: 27.7°C, ветер 6.5 м/с, влажность 65%
k.answer.osm("Хайфа") # Хайфа, נפת חיפה, Хайфский округ, Израиль
k.answer.wiki("Хайфа") # Ха́йфа — третий по величине город Израиля…
k.answer.wikidata("Хайфа") # Хайфа — город на севере Израиля
k.answer.rates("доллар к шекелю") # 1 USD = 2.9728 ILS (ЕЦБ)
k.answer.github("telegram") # DrKLO/Telegram ★29798
То же самое ссылкой: ?only=weather или ?sources=weather.
Просить поле источника — это и значит спросить сам источник: слова «погода» в вопросе может не быть, а погоду вы всё равно хотите.
Умные курсы
k.answer.rates("100 долларов в шекели")
# 100 USD = 297.28 ILS · курс 2.97 · на 2026-08-28, ЕЦБ
k.answer.rates("сколько будет 50 евро в шекелях и долларах")
# 50 EUR = 173.06 ILS, 58.22 USD · курс 3.46 · на 2026-08-28, ЕЦБ
k.answer.rates("100 usd to eur") # то же самое по-английски
Сумму, валюты и их порядок ключ разбирает сам: «100 долларов в шекели» — это из USD в ILS, а не наоборот. Целей может быть несколько. Курсы понимают сумму, порядок и 166 валют — рубль, гривну, тенге, лари, драм и всё остальное; словами или трёхбуквенным кодом:
k.answer.rates("50000 рублей в тенге") # 50 000 RUB = 269 671.85 KZT · курс 5.39
k.answer.rates("1000 гривен в рублях и долларах")
k.answer.rates("100 UZS в KGS") # код работает для всех 166
Работает на двух языках
Язык определяется по самому вопросу: русскими буквами — русские источники, латиницей — английские. Приметы и слова темы разобраны на обоих:
k.answer.text("погода в Хайфе") == k.answer.text("weather in Haifa") # оба идут в погоду
k.answer.text("где находится Хайфа") == k.answer.text("where is Haifa") # оба идут на карту
Чем wiki отличается от wikidata
Это разные вещи, и полезны они в разных случаях:
| что это | пример на «Хайфа» | |
|---|---|---|
wiki |
сводка статьи, написанная людьми — связный текст на несколько предложений | Ха́йфа — третий по величине город Израиля после Иерусалима и Тель-Авива, со смешанным еврейско-арабским населением… |
wikidata |
структурированный факт: название и одна строка «что это за сущность», плюс код вида Q42 | Хайфа — город на севере Израиля, третий по величине город страны |
Проще так: wiki — прочитать, wikidata — разобрать программой. Второй короче,
одинаков на всех языках и удобен, когда нужно понять тип вещи, а не её
описание.
Три способа позвать любой ключ
k.alive("@durov") # весь ответ: объект с полями
k.alive.members_count("@durov") # только одно поле, нужного типа
k.alive.text("@durov") # строка для человека
Аргументы
Keys(...) — подключение
| Аргумент | По умолчанию | Что делает |
|---|---|---|
token |
KEYS_API_KEY, иначе публичный ключ с сервера |
ключ доступа; передаётся только заголовком |
base |
https://monoblock.casa/keys |
адрес сервера |
timeout |
20.0 |
сколько ждать ответа, секунд |
retries |
1 |
повторов при обрыве связи (отказ сервера не повторяется) |
user_agent |
monokeys/<версия> |
как представляться серверу |
k = Keys(timeout=5, retries=2)
k.<ключ>(...) — вызов
| Аргумент | По умолчанию | Что делает |
|---|---|---|
value |
— | главное значение: ссылка или @username |
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) # не ждать дольше трёх секунд
Что можно спросить у клиента
| Вызов | Что вернёт |
|---|---|
k.names() |
имена всех доступных ключей |
k.fields("alive") |
какие поля возвращает ключ |
k.alive.fields() |
то же самое, короче |
k.catalog(refresh=True) |
полный каталог с описаниями, спросить заново |
k.call("alive", "@durov") |
позвать ключ, имя которого известно только в рантайме |
Ответ
Answer — это словарь, который умеет отвечать и как объект:
res = k.alive("@durov")
res.title == res["title"] # одно и то же
bool(res) # True, если ключ ответил утвердительно
dict(res) # обычный словарь
Опечатка не молчит:
res.tittle
# AttributeError: в ответе нет поля 'tittle'; есть: username, url, is_alive, ...
k.alive.members_cout("@durov")
# AttributeError: у ключа 'alive' нет поля 'members_cout'; есть: is_alive, kind, ...
Ошибки
| Исключение | Когда |
|---|---|
AccessDenied |
ключ неизвестен, отозван или отправлен не по HTTPS |
Unavailable |
сервер занят или источник не ответил — осмысленно повторить |
KeysError |
всё остальное: нет такого ключа, мусор на входе |
У всех есть .status и .body. Первые два — потомки KeysError, ловятся
одним except.
from monokeys import Keys, AccessDenied, Unavailable
try:
res = k.alive("@durov")
except AccessDenied:
print("ключ доступа не подошёл")
except Unavailable:
print("сейчас занято, попробую позже")
Методы не зашиты в клиент
Список ключей и их полей приходит с сервера, поэтому новый ключ доступен сразу, без обновления пакета:
k.names() # ['alive', 'answer']
k.несуществующий # AttributeError со списком существующих
Ключ доступа
Заводить не нужно — публичный работает у всех и без счётчика. Свой нужен только
тем, кому нужен собственный рубильник; его выдаёт владелец сервиса, и он тоже
бессрочный. Положите в .env:
KEYS_API_KEY=kx_...
Отозвать свой ключ, если он утёк:
curl -X POST -H "Authorization: Bearer kx_..." https://monoblock.casa/keys/token/revoke
Если ставить пакет не хочется
Тот же самый файл можно просто скачать — из него и собран пакет:
curl https://monoblock.casa/keys/sdk/python > monokeys.py
А можно вообще без клиента — ключ это обычная ссылка:
https://monoblock.casa/keys/alive/@durov -> жив · channel · Pavel Durov · …
Документация целиком: https://monoblock.casa/keys/client
Исходники: https://github.com/monorez3/keys
Metadata
Release files for monokeys 0.2.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| monokeys-0.2.7.tar.gz | 10.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| monokeys-0.2.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 21.4 kB
Release files / monokeys-0.2.7.tar.gz
| Download URL | monokeys-0.2.7.tar.gz |
|---|---|
| Size | 10.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
479cc7413f50005c33da8915ba68cac1c52cc3c8f8729801376929b5a1820e75
|
|
BLAKE2b-256 checksum How to use checksums |
9e1410db9582332fe7d68fed1ba2a79b3561cd388185d874aabdcc07e645689a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency logRelease files / monokeys-0.2.7-py3-none-any.whl
| Download URL | monokeys-0.2.7-py3-none-any.whl |
|---|---|
| Size | 11.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
55ad795950c46e42e16dcd572a98e9c3ccd038112b64b33c77bb18c98485544f
|
|
BLAKE2b-256 checksum How to use checksums |
f8a4bafd8a1e48b124d2301fe7337f3e2ac11e95bce1db5efa2338e944ff09d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency log