Metadata-Version: 2.1
Name: teledev
Version: 0.1.4
Summary: An independent Telegram Bot API framework for Python (Bot API 10.2): message reactions, forum topics, inline mode, payments (incl. Telegram Stars), chat administration, a middleware pipeline, FSM support, rate limiting, webhook and Mini App helpers, plus companion DB/HTTP toolkits
Author: XNar
License: MIT
Keywords: telegram,bot,api,teledev,fsm,forum-topics,reactions,payments,webapp
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Communications :: Chat
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Provides-Extra: db
Provides-Extra: dev
Provides-Extra: http
License-File: LICENSE

# TeleDev

**TeleDev** — независимый фреймворк для Telegram-ботов на Python: декораторы
для хендлеров, встроенный middleware, FSM, автоматические повторы при сбоях
сети и flood control, ограничение скорости отправки, платежи (включая
Telegram Stars), вебхуки и валидация Mini App данных «из коробки». Плюс два
спутника — **teledevdb** (хранилище данных) и **teledevhttp** (HTTP-клиент
для внешних API).

Версия **0.1.4** покрывает актуальный срез Telegram Bot API (**10.2**),
который используют современные клиенты Telegram (проверено на релизе
**12.9.0 (6966)**).

---

## Установка

```bash
pip install teledev
```

Единственная обязательная зависимость — `requests`. `teledevdb` и
`teledevhttp` идут в комплекте, ставить их отдельно не нужно.

---

## Быстрый старт

```python
import os
from teledev import TeleDev, types

bot = TeleDev(os.environ["TELEGRAM_TOKEN"], parse_mode="HTML")

@bot.command("start", description="запустить бота")
def send_welcome(message):
    kb = types.InlineKeyboardMarkup()
    kb.add(types.InlineKeyboardButton("Нажми меня", callback_data="hello"))
    bot.send_message(message.chat_id, "Привет! Я бот на TeleDev 🚀", reply_markup=kb)

@bot.callback_query_handler(func=lambda c: c.data == "hello")
def handle_hello(call):
    bot.answer_callback_query(call.id, text="Привет в ответ!")
    bot.send_message(call.message.chat_id, "Ты нажал на кнопку!")

@bot.message_handler(func=lambda m: True, content_types=["text"])
def echo_all(message):
    bot.send_message(message.chat_id, message.text)

bot.infinity_polling()
```

---

## Что нового в 0.1.4

| Возможность | Как использовать |
|---|---|
| Платежи и Telegram Stars | `bot.send_invoice(...)`, `@bot.pre_checkout_query_handler()`, `@bot.shipping_query_handler()` |
| Ограничение скорости отправки | включено по умолчанию, `TeleDev(..., rate_limit=False)` для отключения |
| Приём вебхуков без сторонних зависимостей | `from teledev.webhook import run_webhook` |
| Валидация Mini App (`initData`) | `from teledev.webapp import validate_init_data` |
| Тестирование хендлеров без сети | `from teledev.testing import FakeBot` |
| Авто-`/help` | `@bot.command("start", description="...")` → `bot.send_help(chat_id)` |
| Эффекты сообщений | `message_effect_id=` в `send_message` |
| Стикерпаки | `create_new_sticker_set`, `add_sticker_to_set`, `get_sticker_set` и т.д. |

В этой версии также исправлены баги из версий 0.1.0–0.1.3 (см.
[CHANGELOG.md](CHANGELOG.md)) — в частности, порча файлов при повторной
отправке после сетевого сбоя и потенциальное зависание при резком всплеске
сообщений в потоковом режиме.

---

## Отличительные особенности фреймворка

| Фишка | Описание |
|---|---|
| Автоповтор при сетевых сбоях | Экспоненциальный backoff на таймаутах и обрывах соединения, с корректной перемоткой файловых потоков перед повтором |
| Автообработка flood control | HTTP 429 обрабатывается по `retry_after` из ответа Telegram |
| Ограничение скорости отправки | Встроенный `Throttler`: держит ~30 сообщений/сек и ~1/сек в один чат |
| Middleware pipeline | `pre_process`/`post_process` вокруг каждого апдейта |
| Встроенный FSM | `StatesGroup`, `State`, персистентность через `teledevdb` |
| Пул воркеров | Ограниченная очередь потоков с таймаутом вместо голого `Thread` на апдейт |
| Встроенный HTTP-клиент | `teledevhttp` — retry/backoff для походов во внешние API |
| Тестируемость | `teledev.testing.FakeBot` — юнит-тесты хендлеров без сети |

---

## Хендлеры сообщений

```python
@bot.message_handler(commands=["start", "help"])
def cmd(message):
    ...

@bot.message_handler(regexp=r"^привет", content_types=["text"])
def hello(message):
    ...

@bot.message_handler(content_types=["photo"])
def on_photo(message):
    ...

@bot.message_handler(func=lambda m: m.from_user.id == 123456)
def only_admin(message):
    ...
```

Фильтры внутри одного `message_handler` комбинируются через логическое И.
Хендлеры проверяются в порядке регистрации, срабатывает первый подходящий.

---

## Клавиатуры, в том числе Mini App

```python
from teledev import types

kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
kb.add("Кнопка 1", "Кнопка 2")
bot.send_message(chat_id, "Выбери:", reply_markup=kb)

ikb = types.InlineKeyboardMarkup()
ikb.add(types.InlineKeyboardButton("Открыть сайт", url="https://example.com"))
ikb.add(types.InlineKeyboardButton("Открыть Mini App", web_app=types.WebAppInfo("https://example.com/app")))
ikb.row(types.InlineKeyboardButton("Да", callback_data="yes"),
        types.InlineKeyboardButton("Нет", callback_data="no"))
bot.send_message(chat_id, "Подтверждаешь?", reply_markup=ikb)
```

---

## Платежи и Telegram Stars

```python
from teledev.types import LabeledPrice

@bot.command("buy_stars")
def buy(message):
    bot.send_invoice(
        message.chat_id, title="Pro", description="Доступ на месяц",
        payload="order-1", currency="XTR",  # XTR = Telegram Stars
        prices=[LabeledPrice("Pro", 100)],  # 100 звёзд
    )

@bot.pre_checkout_query_handler()
def confirm(query):
    bot.answer_pre_checkout_query(query.id, ok=True)  # ответить за 10 секунд!

@bot.message_handler(func=lambda m: m.content_type == "successful_payment")
def on_paid(message):
    bot.send_message(message.chat_id, "Спасибо за оплату!")
```

---

## Валидация Mini App данных

```python
from teledev.webapp import validate_init_data

data = validate_init_data(init_data_from_frontend, bot_token, max_age_seconds=3600)
if data is None:
    return "невалидные данные", 401
user = data["user"]
```

Проверяет подпись `initData` (HMAC-SHA256) по алгоритму Telegram — защищает
от подделки данных на стороне клиента.

---

## Приём вебхуков

```python
from teledev.webhook import run_webhook

bot.set_webhook(url="https://your-domain.example.com/webhook", secret_token="секрет")
run_webhook(bot, port=8443, path="/webhook", secret_token="секрет")
```

Либо интегрируй с любым своим веб-фреймворком через
`bot.process_webhook_update(raw_json)`.

---

## Тестирование хендлеров без сети

```python
from teledev.testing import FakeBot

bot = FakeBot()

@bot.command("start")
def start(message):
    bot.send_message(message.chat_id, "Привет!")

bot.feed_message("/start")
assert bot.sent_calls[-1][0] == "sendMessage"
```

---

## Реакции на сообщения

```python
@bot.message_handler(func=lambda m: True, content_types=["text"])
def react(message):
    bot.set_message_reaction(message.chat_id, message.message_id, reaction="👍")
```

---

## Темы форумов

```python
@bot.command("new_topic")
def new_topic(message):
    topic = bot.create_forum_topic(message.chat_id, name="Обсуждение")
    bot.send_message(message.chat_id, "Готово!", message_thread_id=topic["message_thread_id"])
```

---

## Инлайн-режим

```python
from teledev.types import InlineQueryResultArticle

@bot.inline_query_handler()
def handle_inline(query):
    results = [InlineQueryResultArticle(id="1", title="Эхо", message_text=query.query)]
    bot.answer_inline_query(query.id, results)
```

---

## Медиагруппы (альбомы)

```python
from teledev.types import InputMediaPhoto

bot.send_media_group(chat_id, [
    InputMediaPhoto("https://example.com/1.jpg", caption="Первое фото"),
    InputMediaPhoto("https://example.com/2.jpg"),
])
```

---

## Администрирование чатов

```python
from teledev.types import ChatPermissions

bot.restrict_chat_member(chat_id, user_id, ChatPermissions(can_send_messages=False))
bot.promote_chat_member(chat_id, user_id, can_pin_messages=True, can_delete_messages=True)
bot.ban_chat_member(chat_id, user_id)

@bot.chat_join_request_handler()
def on_join_request(request):
    bot.approve_chat_join_request(request.chat.id, request.from_user.id)
```

---

## FSM (машина состояний)

```python
from teledev.states import StatesGroup, State

class Registration(StatesGroup):
    waiting_name = State()
    waiting_age = State()

@bot.command("register")
def start(message):
    bot.set_state(message.chat_id, message.from_user.id, Registration.waiting_name)
    bot.send_message(message.chat_id, "Как тебя зовут?")

@bot.message_handler(func=lambda m: bot.get_state(m.chat_id, m.from_user.id) == str(Registration.waiting_name))
def name_step(message):
    bot.set_data(message.chat_id, message.from_user.id, name=message.text)
    bot.set_state(message.chat_id, message.from_user.id, Registration.waiting_age)
    bot.send_message(message.chat_id, "Сколько тебе лет?")
```

По умолчанию состояния хранятся в памяти (`MemoryStateStorage`). Для
персистентности между перезапусками передайте `teledevdb`-хранилище:

```python
from teledev import TeleDev
from teledev.states import DBStateStorage
from teledevdb import SQLiteStorage

bot = TeleDev(TOKEN, state_storage=DBStateStorage(SQLiteStorage("fsm.db")))
```

---

## Middleware

```python
from teledev import BaseMiddleware

class LoggingMiddleware(BaseMiddleware):
    def pre_process(self, message, data):
        print("Входящее сообщение:", getattr(message, "text", message))
        return True  # False — оборвать обработку

    def post_process(self, message, data, exception=None):
        if exception:
            print("Ошибка при обработке:", exception)

bot.add_middleware(LoggingMiddleware())
```

---

## Ограничение скорости отправки

```python
from teledev import TeleDev
from teledev.ratelimit import Throttler

# По умолчанию включено с разумными лимитами (~30/сек глобально, ~1/сек в чат).
bot = TeleDev(TOKEN)

# Свои лимиты:
bot = TeleDev(TOKEN, rate_limit=Throttler(global_rate=20, per_chat_rate=1))

# Полностью отключить (не рекомендуется для массовых рассылок):
bot = TeleDev(TOKEN, rate_limit=False)
```

---

## teledevdb — работа с данными

```python
from teledevdb import JSONStorage, SQLiteStorage

db = SQLiteStorage("bot.db")   # или JSONStorage("bot.json")

db.set("user:123:name", "Иван")
print(db.get("user:123:name"))          # "Иван"
db.increment("user:123:messages")       # атомарный счётчик
db.delete("user:123:name")
print(db.all())                         # весь словарь целиком
```

`JSONStorage` и `SQLiteStorage` реализуют один и тот же интерфейс
(`get/set/delete/all/increment`), поэтому взаимозаменяемы, а `SQLiteStorage`
дополнительно даёт `execute()`/`query()` для произвольного SQL.

---

## teledevhttp — запросы к внешним API

```python
from teledevhttp import HttpClient, HttpError

api = HttpClient(base_url="https://api.example.com", timeout=5, max_retries=3)

@bot.command("status")
def status(message):
    try:
        data = api.get_json("status")
        bot.send_message(message.chat_id, f"Статус: {data['status']}")
    except HttpError as e:
        bot.send_message(message.chat_id, f"Ошибка запроса: {e}")
```

`HttpClient` держит один `requests.Session` (переиспользование соединений),
сам делает retry с экспоненциальным backoff на сетевых ошибках, 5xx и 429
(с уважением к заголовку `Retry-After`).

---

## Структура проекта

```
teledev/         # ядро: бот, типы, хендлеры, FSM, middleware,
                 # rate limiting (ratelimit.py), вебхуки (webhook.py),
                 # Mini App валидация (webapp.py), тестирование (testing.py)
teledevdb/       # JSON / SQLite хранилища
teledevhttp/     # HTTP-клиент для внешних API
examples/        # готовые примеры (echo, FSM, БД, HTTP, реакции, темы,
                 # инлайн, платежи, вебхуки, Mini App, тестирование)
docs/            # документация
tests/           # unit-тесты
```

Больше примеров — в папке [`examples/`](examples), подробная документация —
в [`docs/`](docs), список изменений по версиям — в [`CHANGELOG.md`](CHANGELOG.md).

## Лицензия

MIT — см. [LICENSE](LICENSE).
