Metadata-Version: 2.5
Name: xmali-sdk
Version: 0.1.0
Summary: Typed XMali financial statements API client with exact Decimal, sync and async support
Project-URL: Homepage, https://xmali.ir/
Project-URL: Documentation, https://xmali.ir/docs/api/
Author: XMali
License-Expression: MIT
License-File: LICENSE
Keywords: codal,finance,financial-statements,xmali
Classifier: Development Status :: 4 - Beta
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: anyio<5,>=4.14.2
Requires-Dist: httpx2<3,>=2.14.0
Requires-Dist: pydantic<3,>=2.12.0
Provides-Extra: polars
Requires-Dist: polars<3,>=2.0.0; extra == 'polars'
Description-Content-Type: text/markdown

# XMali Python SDK

Typed, read-only financial statements for one Iranian listed company per request.
Get income statements, balance sheets and cash flow statements with exact Decimal
amounts, fiscal periods, audit/publication metadata and official Codal source links.

## Install

Python3.11–3.15. Install **0.1.0** of the public distribution with uv:

```sh
uv add xmali-sdk==0.1.0
```

Or with pip:

```sh
python -m pip install xmali-sdk==0.1.0
```

The Python import is `xmali`. Polars is not installed or imported by default.
See [the installation guide](https://xmali.ir/docs/api/index.html#installation).

If you installed an earlier `xmali` direct wheel or private `xmali-fundamentals`
distribution, remove both with `python -m pip uninstall xmali xmali-fundamentals`
using the same interpreter before installing `xmali-sdk`. These distributions
own overlapping module files and must not be co-installed.

Restart your Jupyter kernel after installation. No database or telemetry is installed.

## Get financial statements

Create a personal read key in your [XMali API-key page](https://xmali.ir/api/keys). Set
`XMALI_API_KEY` privately, or use `getpass` as below. Never put a key in source,
URLs, notebook outputs or logs. API eligibility/quota and data rights are separate
from the MIT license for this client.

```python
from getpass import getpass
from xmali import RESTClient

with RESTClient(
    getpass("XMali API key: "),
) as client:
    income = client.list_financials_income_statements(
        ticker="قپیرا", timeframe="annual", scope="standalone", max_items=4,
    ).collect()
    balances = client.list_financials_balance_sheets(ticker="قپیرا", max_items=4).collect()
    cash = client.list_financials_cash_flow_statements(ticker="قپیرا", max_items=4).collect()

# Typed records work with plain Python after closing the client.
for row in income:
    print(row.model_dump_json(indent=2))
```

For optional local DataFrame conversion, install the extra only when needed:

```sh
uv add "xmali-sdk[polars]==0.1.0"
```

```python
frame = income.to_polars()
```

Without Polars, conversion raises an informative `ImportError` with that command;
requesting, iterating and inspecting exact typed records still work normally.

The default base is `https://xmali.ir/api/v1/`. For a running local deployment,
pass `base_url="http://127.0.0.1:8001/api/v1/"` explicitly. Create a key in the
same environment you intend to query. Account eligibility and quota apply to every request.

Every financial and coverage query requires one exact `ticker` string. Omission,
empty strings, arrays and comma-separated symbols fail before HTTP. Defaults are
annual and standalone. Income/cash flow support qualified quarterly, YTD and TTM;
balance sheets are annual/quarterly snapshots. Missing values remain null;
amounts use their verified base unit, and EPS retains its per-share unit. Never
apply the source scale twice or infer unavailable figures.

The interactive reference starts with `قپیرا`; edit the symbol to query another company.

## Pagination and async

`limit` is page size (default/max100), while `max_items` caps total collected rows.
A fresh cursor is lazy; `collect()` fetches pages once and returns a re-iterable
result. Inspect `result.stop_reason` and `result.has_more` for cap versus exhaustion.
Each fetched page/retry has its normal API quota cost. Page errors raise; no hidden
restart or successful partial result is returned. `AsyncRESTClient` supports
`async with` and `await cursor.collect()` with the same query/precision contract.

`client.issuers.list(q=...)`, `client.coverage(family=..., ticker=...)` and
`client.fields(family=...)` expose company discovery, measured availability and
the dictionary. Existing `xmali_fundamentals` imports retain their separate older
reported-statement semantics; new applications should use `xmali`.

## Documentation and security

[Financial statement reference](https://xmali.ir/docs/api/) contains the three complete statement families, Python/REST examples, Persian
item meanings and actual-query JSON. No notebooks or fabricated financial values
are published. Internal source captures remain excluded from public archives.

Use context managers or close clients explicitly. Total deadlines bound retries,
backoff and response-body reads; TLS verification stays on and redirects are
refused. Ambient proxies/certificates are disabled unless explicitly enabled.
Injected clients remain caller-owned unless ownership is transferred. HTTP errors
retain safe status/code/request IDs, never credentials or response bodies.

This release is MIT-licensed SDK code. It grants no financial-data license, API
subscription, server-code license, historical as-of archive, trading, provider
access, FX conversion or financial-template coverage beyond actual API evidence.

`line_items` contains the actual report-relevant items with `name`, `label_fa`,
`label_en`, exact `amount`/`unit` and availability `status`. Zero is preserved;
source-backed unavailable values retain null and a reason. The cross-format
field dictionary is not expanded into each company's response. `reports`
contains official Codal URLs and report headers, without extraction data or
internal identifiers. Default `to_polars()` uses the union of actual returned
items; pass `fields=[...]` for an explicit subset. `include_provenance=True`
adds only `reports_json`. Financial proof checks remain on the server.

`ticker` is canonical; the deprecated `tickers` keyword remains a single-symbol
input compatibility alias. Supplying both is rejected before HTTP. JSON query
metadata emits only `ticker`.
