Metadata-Version: 2.5
Name: madeenan-sdk
Version: 0.1.0
Summary: Typed Python client for the Madeenan Quran and Hadith API: source search, Quran, Hadith, Tafsir, and dua lookups, quote search, and cited chat
Project-URL: Homepage, https://madeenan.com
Project-URL: Documentation, https://madeenan.com/docs/sdk-examples
Project-URL: Repository, https://github.com/itsmunzir/madeenan
Project-URL: Pricing, https://madeenan.com/pricing
Author: Madeenan
License-Expression: MIT
License-File: LICENSE
Keywords: api,citations,dua,hadith,islam,islamic,mcp,quran,rag,sdk,tafsir
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Religion
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: httpx<1,>=0.27
Requires-Dist: pydantic<3,>=2.8
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.3; extra == 'dev'
Requires-Dist: ruff>=0.9; extra == 'dev'
Description-Content-Type: text/markdown

# Madeenan Python SDK

Typed Python client for the Madeenan Quran and Hadith API. Search Quran, Hadith, Tafsir, and dua sources, read exact references, check quotes, and get cited chat answers. Docs: [madeenan.com/docs](https://madeenan.com/docs).

- [Quran API overview](https://madeenan.com/quran-api)
- [Hadith API overview](https://madeenan.com/hadith-api)
- [SDK examples](https://madeenan.com/docs/sdk-examples)
- [API reference](https://madeenan.com/docs/api)
- [Pricing](https://madeenan.com/pricing)

`madeenan-sdk` has sync and async clients. It needs Python 3.11 or newer.

## Install

```shell
python -m pip install madeenan-sdk
```

To install from a checkout of the Madeenan repository instead, run this
command from the repository root:

```shell
python -m pip install -e ./packages/python
```

## Configure the client

The default API URL is `https://api.madeenan.com`. Chat requires an API key.
Search permits anonymous access, subject to server limits. Set
`MADEENAN_API_KEY`, or pass `api_key` when you create a client. The SDK sends
the key in the `X-Madeenan-API-Key` header. Public source lookups and quote
search do not need a key.

```shell
export MADEENAN_API_KEY="your-api-key"
```

You can pass a custom API URL with `base_url` or set
`MADEENAN_API_BASE_URL`. The client accepts a URL with or without the `/v1`
suffix.

The default timeout is 30 seconds. Pass a timeout in seconds, or pass an
`httpx.Timeout` object for separate connect, read, write, and pool timeouts.
Numeric timeout values must be greater than zero and no more than 300 seconds.

```python
from madeenan_sdk import MadeenanClient

with MadeenanClient(
    base_url="https://api.example.com",
    timeout=10,
) as client:
    result = client.quran_verse("2:153")
```

You can also set `MADEENAN_TIMEOUT` to a number of seconds.

## Search and read sources

Search returns results grouped by source index. Pass `indexes` to limit the
search. You can also call a source method when you know its reference.

```python
from madeenan_sdk import MadeenanClient

with MadeenanClient() as client:
    response = client.search("patience in adversity", indexes=["quran", "hadith"])
    for index, results in response.results.items():
        for result in results:
            print(index, result.ref, result.translation)

    verse = client.quran_verse("2:153")
    print(verse.arabic, verse.translation)

    passage = client.quran_passage(2, start=153, end=157)
```

Use `quran_chapter(surah_number)`, `quran_passage(...)`,
`hadith(collection_slug, hadith_number)`, or `dua(collection_slug, item_id)` for
other source lookups. Use `quote_search(text)` to find wording in sources.

## Chat

Chat requires a Madeenan API key. It uses Madeenan hosted chat and its chat
quota. The `chat()` method does not accept a model-provider key. For a
bring-your-own-model flow, call `search()` and pass its source results to your
model from your application.

```python
from madeenan_sdk import MadeenanClient

with MadeenanClient() as client:
    response = client.chat("Find Quran sources about patience", indexes=["quran"])
    print(response.answer)
    for citation in response.citations:
        print(citation.citation_label, citation.source_id)
```

The sync client supports chat streams. Each event has an `event` name and
`data`. The event name can be `source`, `token`, `done`, `error`, or `message`.
Check for an `error` event in the stream. Network and HTTP errors raise Python
exceptions.

```python
from madeenan_sdk import MadeenanClient

with MadeenanClient() as client:
    for event in client.chat_stream(message="Find Quran sources about patience"):
        if event.event == "token":
            print(event.data.get("token", ""), end="", flush=True)
        elif event.event == "error":
            print(event.data)
```

`client.chat(message, stream=True)` also returns a sync event iterator.

## Async client

The async client has the same search and source methods. Use `await` for
requests and `async for` for streams.

```python
import asyncio

from madeenan_sdk import AsyncMadeenanClient

async def main():
    async with AsyncMadeenanClient() as client:
        verse = await client.quran_verse("2:153")
        response = await client.chat("Find Quran sources about patience", indexes=["quran"])
        print(verse.translation, response.answer)

        async for event in client.chat_stream(message="Find Quran sources about patience"):
            if event.event == "token":
                print(event.data.get("token", ""), end="", flush=True)

asyncio.run(main())
```

`await client.chat(message, stream=True)` returns an async event iterator.

## Errors

All SDK errors inherit from `MadeenanError`. HTTP errors use specific
subclasses: `AuthenticationError`, `RateLimitError`, `NotFoundError`, or
`APIError`. `TimeoutError` reports a request timeout. `RequestError` reports
other request failures. `ConfigurationError` reports invalid local input or
options.

Each error has `code`, `status_code`, and `request_id` fields. Some fields can
be `None`. The error message does not include your API key or request text.

```python
from madeenan_sdk import MadeenanClient, MadeenanError

try:
    with MadeenanClient() as client:
        client.search("patience", indexes=["quran"])
except MadeenanError as error:
    print(error.code, error.status_code, error.request_id)
```

The SDK does not retry requests. This also applies to chat requests.

## License

MIT. Source text and translations returned by the API keep their own edition
attribution; see [Attribution](https://madeenan.com/docs/attribution).
