# Python kütüphanesi (`noluyo-bot`)

`noluyo-bot` (içe aktarma adıyla `noluyo_bot`), N'oluyo bot platformunun **Python 3.11 ve üstü** için geliştirilmiş resmi `asyncio` kütüphanesidir. Çalışma zamanında yalnızca `aiohttp` kullanır, PEP 561 (`py.typed`) tip bildirimleriyle gelir ve MIT lisanslıdır.

## Kurulum

Sanal ortam oluşturup paketi kur (HTTP imza doğrulaması veya ses yayını kullanacaksan isteğe bağlı ekleri ekle):

```bash
python3 -m venv .venv
source .venv/bin/activate   # Windows PowerShell: .venv\Scripts\Activate.ps1
pip install noluyo-bot

# İsteğe bağlı ekler:
pip install "noluyo-bot[http]"    # Ed25519 HTTP etkileşim doğrulaması (cryptography)
pip install "noluyo-bot[voice]"   # Ses kanallarında yayın (livekit)
```

> **Not:** Sıfırdan Python, sanal ortam ve `.env` kurulumu için [Kurulum](https://noluyo.net/gelistirici/kurulum.md) sayfasındaki adımları izleyebilirsin.

## İlk bot

Paket PyPI'da `noluyo-bot` adıyla kurulur, Python kodunda alt çizgiyle `import noluyo_bot` olarak içe aktarılır. Token'ı koda yazma; `os.environ["BOT_TOKEN"]` ile ortamdan oku:

```py title=bot.py
import os
import noluyo_bot

bot = noluyo_bot.Client(
    token=os.environ["BOT_TOKEN"],
    intents=noluyo_bot.Intents.GUILDS
    | noluyo_bot.Intents.GUILD_MESSAGES
    | noluyo_bot.Intents.MESSAGE_CONTENT,
)

@bot.on("READY")
async def on_ready(ready):
    print(f"{ready['user']['username']} bağlandı")

@bot.on("MESSAGE_CREATE")
async def on_message(message):
    if message["author"].get("bot"):
        return
    if message["content"] == "!merhaba":
        await bot.rest.create_message(message["channel_id"], {"content": "Merhaba!"})

@bot.interactions.on("ping")
async def on_ping(i):
    await i.reply({"content": "Pong!"}, ephemeral=True)

@bot.on("READY")
async def sync_commands(_ready):
    await bot.commands.sync([
        {"name": "ping", "description": "Botun yanıt verip vermediğini sınar"},
    ])

bot.run()
```

Zaten çalışan bir `asyncio` döngüsünün içindeysen `bot.run()` yerine `await bot.start()` ve kapatırken `await bot.close()` kullanabilirsin.

## Gateway olayları ve TypedDict veri modeli

`@bot.on("OLAY_ADI")` dekoratörü [Gateway](https://noluyo.net/gelistirici/gateway.md) üzerindeki tüm olayları dinler. Python kütüphanesi gelen JSON verisini ağır sınıf hiyerarşilerine sarmalamaz; alan adları dokümandaki JSON anahtarlarıyla (`message["channel_id"]`, `member["user"]["id"]`) birebir aynı `TypedDict` sözlükleri olarak gelir:

- **Bağlantı ve sunucular:** `READY`, `RESUMED`, `GUILD_CREATE`, `GUILD_UPDATE`, `GUILD_DELETE`
- **Mesajlar ve tepkiler:** `MESSAGE_CREATE`, `MESSAGE_UPDATE`, `MESSAGE_DELETE`, `MESSAGE_REACTION_ADD`, `MESSAGE_REACTION_REMOVE`
- **Üyeler, roller ve kanallar:** `GUILD_MEMBER_ADD`, `GUILD_MEMBER_UPDATE`, `GUILD_MEMBER_REMOVE`, `CHANNEL_CREATE`, `CHANNEL_UPDATE`, `CHANNEL_DELETE`, `GUILD_ROLE_CREATE`, `GUILD_ROLE_UPDATE`, `GUILD_ROLE_DELETE`
- **Etkileşim ve ses:** `INTERACTION_CREATE`, `VOICE_STATE_UPDATE`, `VOICE_SERVER_UPDATE`, `VOICE_JOIN_ERROR`

Dinleyici fonksiyon tek argüman (`data`) ya da iki argüman (`data, meta` — `meta["shard_id"]` ve `meta["seq"]`) alabilir. İhtiyacın olan intent bitlerini [Intent'ler](https://noluyo.net/gelistirici/intentler.md) rehberinden seç.

## REST çağrıları (`bot.rest`)

OpenAPI şemasındaki her `operationId`, `bot.rest` üzerinde `snake_case` adıyla `async` bir metottur:

```py
from pathlib import Path

# Metin ve embed gönderme:
await bot.rest.create_message(
    channel_id,
    {
        "content": "Haftalık özet hazır.",
        "embeds": [{"title": "Özet", "description": "12 yeni üye katıldı.", "color": 0x3366FF}],
    },
)

# Dosya ekiyle birlikte attachment:// görselli embed gönderme:
await bot.rest.create_message(
    channel_id,
    {
        "embeds": [{"title": "Grafik", "image": {"url": "attachment://grafik.png"}}],
        "files": [
            {
                "name": "grafik.png",
                "data": Path("./grafik.png").read_bytes(),
                "content_type": "image/png",
            }
        ],
    },
)

# Üyeye rol verme ve 10 dakikalık zaman aşımı uygulama:
from datetime import datetime, timedelta, timezone

until = (datetime.now(timezone.utc) + timedelta(minutes=10)).isoformat()
await bot.rest.add_member_role(guild_id, user_id, role_id)
await bot.rest.update_member(guild_id, user_id, {"communication_disabled_until": until})
```

Gateway açmadan yalnızca HTTP istekleri atmak için `async with noluyo_bot.Rest(token=os.environ["BOT_TOKEN"]) as rest:` bağlam yöneticisini kullanabilirsin. Görsel ve alan sınırları [Embed'ler](https://noluyo.net/gelistirici/embedler.md) rehberindedir.

## Komut kaydı ve etkileşimler

`await bot.commands.sync(liste)` küresel komutlarını tek çağrıda eşitler (`guild_id=...` verirsen yalnızca o sunucunun komutlarını günceller).

`@bot.interactions.on(ad_veya_desen)` dekoratörü [Komutlar](https://noluyo.net/gelistirici/komutlar.md), [Bileşenler](https://noluyo.net/gelistirici/bilesenler.md) (`custom_id`) ve [Formlar](https://noluyo.net/gelistirici/formlar.md) etkileşimlerini yönlendirir; tam metin ya da derlenmiş `re.compile(r"^anket:")` verebilirsin:

```py
import re

@bot.interactions.on("duyuru")
async def on_announce(i):
    baslik = i.option("baslik")
    await i.defer(ephemeral=True)
    await bot.rest.create_message(
        i.channel_id,
        {"embeds": [{"title": str(baslik), "description": "Yeni duyuru yayınlandı."}]},
    )
    await i.edit_reply({"content": "Duyuru kanala gönderildi."})

@bot.interactions.on(re.compile(r"^anket:"))
async def on_poll_vote(i):
    secim = i.data["custom_id"].split(":", 1)[1]
    await i.reply({"content": f"Oyun kaydedildi: {secim}"}, ephemeral=True)
```

`InteractionContext` üzerindeki yardımcılar: `i.option(ad)`, `i.fields()`, `await i.reply(..., ephemeral=...)`, `await i.defer(ephemeral=...)`, `await i.defer_update()`, `await i.update(...)`, `await i.edit_reply(...)`, `await i.delete_reply()`, `await i.follow_up(...)`, `await i.show_modal(...)` ve [Otomatik tamamlama](https://noluyo.net/gelistirici/otomatik-tamamlama.md) için `await i.autocomplete(secenekler)`. Ayrıntılar [Etkileşimler](https://noluyo.net/gelistirici/etkilesimler.md) sayfasındadır.

## HTTP modu ve imza doğrulama (`[http]`)

Etkileşimleri HTTPS sunucundan karşılıyorsan ([HTTP ile teslim](https://noluyo.net/gelistirici/http-teslim.md)), `noluyo-bot[http]` ekini kurup Ed25519 imzasını `verify_interaction` ile doğrula:

```py
import os
from noluyo_bot import verify_interaction

gecerli = verify_interaction(
    os.environ["NOLUYO_PUBLIC_KEY"],
    request.headers["X-Signature-Ed25519"],
    request.headers["X-Signature-Timestamp"],
    raw_body_bytes,
)
if not gecerli:
    return Response(status=401, text="invalid signature")
```

## Ses kanallarında yayın (`[voice]`)

`noluyo-bot[voice]` kurulu olduğunda `await bot.voice.join(guild_id, channel_id)` gateway `op 4` ve `VOICE_SERVER_UPDATE` adımlarını yürüterek LiveKit odasına bağlanır:

```py
conn = await bot.voice.join(guild_id, voice_channel_id)
await conn.play_file("./muzik.mp3")
await conn.leave()
```

N'oluyo'da botlar seste **yalnızca yayın yapar**; kütüphane hiçbir uzak ses izine abone olmaz ve kimseyi duyamaz. Ses kuralları ve hata kodları [Ses](https://noluyo.net/gelistirici/ses.md) sayfasındadır.

## Hız sınırı kuyruğu, shard ve güvenlik kuralları

JavaScript kütüphanesiyle birebir aynı çalışma kuralları geçerlidir:

- **Kova kuyruğu ve `429`:** `X-RateLimit-Bucket`, `X-RateLimit-Remaining` ve `X-RateLimit-Reset-After` başlıklarına göre kova bazında sıra korur; `429` durumunda `Retry-After` kadar bekler ve `X-RateLimit-Scope: shared` geldiğinde tüm rotaları birlikte yavaşlatır ([Hız sınırları](https://noluyo.net/gelistirici/rate-limit.md)).
- **Yalnız `GET` tekrarı:** `5xx` hatalarında yalnız `GET` çağrıları en çok 3 kez yeniden denenir; `POST`, `PATCH`, `PUT` ve `DELETE` tekrar edilmez.
- **Shard aralığı ve `RESUME`:** Shard sayısını `/gateway/bot` ucundan alır, `IDENTIFY` çerçevelerini en az **5,1 saniye** arayla gönderir ([Shard'lar](https://noluyo.net/gelistirici/shardlar.md)) ve kopmalarda `op 6` (`RESUME`) ile devam eder.
- **Kalıcı kapanış koruması ve token gizleme:** `4004` ve `4014` gibi `reconnect: false` kapanış kodlarında yeniden bağlanmaya çalışmaz; çözüm ipucu içeren `GatewayCloseError` fırlatır. İstisna metinlerinde (`str`, `repr`, log çıktıları) bot token'ı otomatik olarak `[REDACTED]` ile gizlenir.

## Hata sınıfları ve örnek projeler

Yakalayabileceğin hata sınıfları `noluyo_bot` kökünden dışa aktarılır:

- `NoluyoError`: tüm kütüphane hatalarının taban sınıfı
- `ApiError`: `4xx`/`5xx` yanıtları (`err.status`, `err.code`, `err.errors`, `err.path`)
- `RateLimitedError`: yeniden deneme sınırını aşan `429` yanıtı (`err.retry_after`, `err.scope`)
- `GatewayCloseError`: kalıcı gateway kapanışı (`err.code`, `err.close_name`, `err.hint`)
- `VoiceJoinError`: ses kanalına giriş reddi (`err.code`, `err.guild_id`)

Tam çalışan Python örnek projeleri depoda yer alır:

- `sdks/examples/python/moderasyon`: sözcük süzgeci, `/sustur` zaman aşımı komutu ve denetim embed'i
- `sdks/examples/python/anket`: süreli buton oylaması
- `sdks/examples/python/muzik`: yerel ses dosyası yayınlayan ses botu
- `sdks/examples/python/oauth_site`: PKCE tabanlı "N'oluyo ile giriş" web uygulaması

## Bu sayfayı yapay zekaya verirsen

> **İpucu:** Yapay zekaya Python ile N'oluyo botu yazdırırken bu sayfayı ver ve şu noktaları hatırlat:
>
> - Paket `pip install noluyo-bot` ile kurulur, kodda `import noluyo_bot` olarak içe aktarılır; başka sohbet platformlarının kütüphaneleri kullanılmaz.
> - Olay verileri sınıf nesnesi değil `TypedDict` sözlüğüdür: `message.content` değil, `message["content"]` ve `message["channel_id"]` yazılır.
> - `bot.rest.<snake_case_operation_id>` metotları `async` çalışır (`await bot.rest.create_message(...)`).
> - Token koda yazılmaz; `os.environ["BOT_TOKEN"]` üzerinden okunur.

## Sırada ne var

- [Hazır tarifler](https://noluyo.net/gelistirici/tarifler.md): hem Python hem JavaScript sekmeli 9 çalışan bot örneği
- [JavaScript kütüphanesi](https://noluyo.net/gelistirici/kutuphane-js.md): Node.js 22+ için sıfır bağımlılıklı kütüphane rehberi
- [Botu açık tut](https://noluyo.net/gelistirici/botu-acik-tut.md): Python botunu Linux sunucuda sanal ortam ve `systemd` ile çalıştırma
