Metadata-Version: 2.5
Name: qombra
Version: 0.4.0
Summary: Python SDK for Qombra: Agentic Data Science and QBrain predictive engine for structured data.
Project-URL: Homepage, https://www.qombra.com
Project-URL: Documentation, https://www.qombra.com/api/docs
Author: Qombra Team
License: Copyright (c) 2026 Qombra. All rights reserved.
        
        This software is proprietary. Use of this client library is permitted only in
        connection with a Qombra account and subject to the Qombra terms of service
        (https://www.qombra.com). Redistribution or modification without written
        permission is prohibited.
License-File: LICENSE
Keywords: data-analysis,foundation-model,machine-learning,qbrain,shap,tabular
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: keyring>=24
Requires-Dist: pandas>=2.0
Requires-Dist: pyarrow>=14
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: python-dotenv>=1.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# qombra

Python client for [Qombra](https://www.qombra.com) — data analysis, AI-guided
preprocessing, model training on **QBrain**, inference, zero-shot time series
forecasting, and SHAP explainability, all running on the Qombra platform through
your account.

QBrain is Qombra's proprietary tabular foundation model: it reads the structure
of your data directly, so `fit()` needs a dataframe and a target column — no
architecture to pick, no hyperparameters to tune.

```bash
pip install qombra
```

## Quickstart

```python
import pandas as pd
import qombra

qombra.login()   # opens the browser; approve the SDK session (valid 12 hours)

df = pd.read_csv("customers.csv")

# 1. Dataset statistics (analyzes a ≤1000-row sample with the fewest NaNs)
report = qombra.analyze(df)
print(report.summary, report.warnings)

# 2. Preprocessing with a natural-language instruction
result = qombra.preprocessing(df, "drop duplicate rows and outliers in price")
print(result)          # summary, actions, warnings
clean_df = result.df

# 3. Training — the model stays on the server, addressed by id
model = qombra.fit(clean_df, target="churn_30d")
print(model.id, model.metrics)
# Optional: pick the evaluation metric and the compute budget yourself
model = qombra.fit(clean_df, target="churn_30d", metric="roc_auc", effort="high")

# 4. Inference
predictions = model.predict(clean_df.head(100))

# 5. Explainability (SHAP)
print(model.explain())

qombra.logout()  # revoke the session token
```

### Later, in another session — no retraining

```python
import qombra

qombra.login()
model = qombra.Model.from_id("«the model id from earlier»")
predictions = model.predict(new_rows)
```

### Session management

There are two ways to authenticate, for the two ways people use the API.

**Interactive — `qombra.login()`.** Opens a browser window where you sign in on
the web app and approve the SDK; the resulting session lives in your OS keyring
and expires after 12 hours. Close it explicitly, or scope it with `with`
(leaving the block ends the session):

```python
qombra.login()
with qombra.Qombra() as client:
    model = client.fit(df, target="price")
    print(client.whoami())   # remaining quotas
# session ended here
```

No browser available (SSH, CI)? Use `qombra.login(headless=True)` and
copy-paste the code shown on the consent page.

**Production — an API key.** For systems that must run unattended, a key never
expires and needs no browser. Create one in the Qombra app under
**Account → API keys**, then put it in the environment or in a `.env` file in
your project (the environment wins when both are set):

```bash
export QOMBRA_API_KEY=qbk_…
```

```python
import qombra
preds = qombra.predict(model_id, new_rows)   # no login() call
```

The key is shown once at creation — store it in your secret manager. It stays
valid until you revoke it in the same place; rotate by creating a new key,
deploying it, then revoking the old one. `close()` never revokes an API key, so
a `with` block cannot take your service offline.

API keys are available on accounts enabled for production access; the tab
appears in the app once Qombra switches it on for you.

### The full pipeline in one call

```python
result = qombra.auto_run(df, "Predict which customers churn in the next 30 days")
print(result)                     # phases, target, test metric
preds = result.model.predict(new_rows)
```

`auto_run` drives the same agent workflow as the web app (ingest →
preprocessing → target confirmation → training) without a human in the loop.
Expect minutes to hours; the created analysis is fully browsable in the web
app afterwards.

### Forecasting time series

QBrain forecasts zero-shot: hand it the history and it returns the forecast —
no training step, no model id, nothing to delete afterwards.

```python
# sales: one row per store and day — store, date, units, price, promo
fc = qombra.forecast(
    sales, target="units", horizon=14,
    timestamp_column="date", id_column="store",
    future=planned,                       # store, date, price, promo for the next 14 days (optional)
    groups={"north": ["s1", "s2", "s3"]}, # related series inform each other (optional)
    non_negative=True,                    # units can't go below zero
)
fc.frame.head()          # store, date, target, forecast, forecast_q05, forecast_q50, forecast_q95
fc.wide()                # one column per store, one row per forecast day
fc.wide(quantile=0.95)   # the upper band
print(fc.warnings)       # duplicates dropped, gaps filled, series skipped, ...
```

- **Long format.** One row per observation; every column that is not the id,
  the timestamp or a target is a *past covariate* (numeric or categorical).
  Leave `id_column` unset for a single series.
- **Future covariates** go in `future`: the id and timestamp columns plus the
  covariate columns, one row per series per forecast step, starting right after
  each series' last observation. Columns of `df` absent from `future` are
  treated as past-only.
- **Frequency** is inferred per series; pass `freq="W-MON"` (any
  [pandas frequency alias](https://pandas.pydata.org/docs/user_guide/timeseries.html#offset-aliases)) when the data is too gappy to infer from. Gaps are filled, duplicate
  timestamps collapsed (last wins), timezone-aware timestamps moved to UTC.
- **Quantiles**: any number of levels between 0.01 and 0.99; 0.5 is always
  included and is the `forecast` column. Each level adds a column, so many
  levels count against the forecast-values limit.
- **Several targets** (`target=["units", "revenue"]`) are forecast jointly per
  series and share that series' covariates. A target that needs covariates of
  its own is better modelled as its own series (its own id), at the price of
  being forecast independently.
- **Limits per call**: 10,000 series · 100 value columns per series · horizon
  1,024 steps · 20,000,000 data points (history rows × value columns, after
  each series is truncated to its most recent 8,192 steps) · 10,000,000 forecast
  values (series × horizon × targets × (1 + quantile levels)).

A forecast that outlives your client-side `timeout` keeps running server-side;
collect it with `qombra.forecast_result(e.job_id)` from the `JobTimeoutError`.
Ctrl+C or `qombra.stop(job_id)` cancels it.

### Managing stored artifacts

```python
qombra.list_models()                     # all trained models in your account
qombra.delete_model(model)               # irreversible
qombra.list_preprocessing_results()
qombra.delete_preprocessing_result(job_id)
```

## Error handling

All errors derive from `qombra.QombraError`:

```python
try:
    model = qombra.fit(df, target="revenue")
except qombra.AuthenticationError:
    qombra.login()                       # token expired (12h) — sign in again
except qombra.QuotaExceededError as e:
    print("Usage limit reached:", e)
except qombra.ValidationError as e:
    print("Bad input:", e.code, e)
except qombra.JobTimeoutError as e:
    print("Still training server-side, job:", e.job_id)
```

Notable classes: `AuthenticationError`, `QuotaExceededError`,
`ValidationError` (with a machine-readable `.code`), `PayloadTooLargeError`,
`NotFoundError`, `JobFailedError`, `JobTimeoutError`, `NetworkError`,
`ServerError`.

## Data format & metering

Dataframes travel as parquet with plain scalar columns (numbers, booleans,
strings, dates, timestamps, decimals; pandas categoricals are fine) — cast
mixed-type `object` columns before upload. Uploads are size-capped and calls
are rate-limited: an oversized upload raises `PayloadTooLargeError` (reduce or
batch it), rapid-fire calls raise `RateLimitedError`.

All SDK usage counts toward the same account limits the web app uses:

- `preprocessing` spends **LLM output tokens** (the AI agent's work) plus one
  chat message, charged once per call.
- `fit` creates one analysis, counted against your analysis limit. QBrain is
  not an LLM, so training spends no output tokens.
- `auto_run` spends all three: one analysis, plus the chat messages and output
  tokens the agent consumes across the run.
- `analyze`, `predict`, `forecast`, `explain` and the listing calls spend no
  quota; they are rate-limited instead (`predict` and `forecast` share one
  hourly limit).

Check what is left with `qombra.whoami()`.

## Support

Questions and issues: [www.qombra.com](https://www.qombra.com) — or reach out
at [hey@qombra.com](mailto:hey@qombra.com).
