Metadata-Version: 2.4
Name: yousleep_common
Version: 12.10.0
Summary: YouSleep Common
Project-URL: Homepage, https://yousleep.ai
Project-URL: Source, https://github.com/yousleep-ai/common
Project-URL: Issues, https://github.com/yousleep-ai/common/issues
Author-email: Mathias Perslev <mp@yousleep.ai>
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: api-client,edf,eeg,polysomnography,sdk,sleep
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Healthcare Industry
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: gitpython>=3.1.47
Requires-Dist: httpx>=0.28.1
Requires-Dist: mkdocs-gen-files>=0.6.0
Requires-Dist: numpy>=2.0.0
Requires-Dist: pydantic[email]>=2.12.5
Requires-Dist: pyyaml>=6.0.3
Provides-Extra: system
Requires-Dist: nvidia-ml-py>=13.590.44; extra == 'system'
Description-Content-Type: text/markdown

# YouSleep Python SDK

**Type-safe async Python SDK and shared models for the [YouSleep](https://yousleep.ai) sleep analysis platform.**

Analyze a sleep recording in three lines:

```python
from yousleep_common.client import AsyncClient

async with AsyncClient(base_url="https://api.yousleep.ai", token="...") as client:
    result = await client.workflows.analyze_file(
        file="night.edf", analysis_config_id="u-sleep-research-v1"
    )
    print(result.biomarkers.total_sleep_time, len(result.events))
```

## Features

- **High-level workflows** — one call to upload, analyze, and fetch results;
  ephemeral variants clean up everything they created, even on exceptions
- **Multi-file batch scoring** — analyze hundreds of recordings in one call
  (bounded by the server's batch limits) with per-file outcomes that never
  abort the whole batch
- **Full API coverage** — projects, studies, recordings, analyses, batch
  operations, reports, billing; verified against the server's OpenAPI spec in CI
- **Streaming uploads** — presigned S3 flow with 64 KiB chunking and progress
  callbacks; files never load fully into memory
- **Typed end to end** — Pydantic v2 request/response models, `py.typed`,
  strict-mypy clean
- **Robust by default** — JWT auth with automatic token refresh, retries with
  exponential backoff, rate-limit handling, and a precise exception hierarchy
  (including distinct quota and credit errors)

## Installation

```bash
pip install yousleep-common
```

Requires Python 3.12+.

## Quick start

### Authenticate

```python
from yousleep_common.client import AsyncClient
from yousleep_common.models import UserAuthentication

client = await AsyncClient.from_credentials(
    base_url="https://api.yousleep.ai",
    credentials=UserAuthentication(email="you@example.com", password="..."),
)
```

Or pass a JWT directly: `AsyncClient(base_url=..., token=...)`.

### Analyze a file end-to-end

```python
result = await client.workflows.analyze_file(
    file="night.edf",
    analysis_config_id="u-sleep-research-v1",
    study_name="Subject 001",   # optional; inferred from filename if omitted
    age=35, sex="male",         # optional subject metadata
)
result.events      # list[Event]
result.biomarkers  # BiomarkerResult (TST, SE, SOL, WASO, ...)
```

Need it gone afterwards? The temporary variant deletes everything it created
on exit — including on errors:

```python
async with client.workflows.analyze_file_temporary(
    file="night.edf", analysis_config_id="u-sleep-research-v1"
) as result:
    export(result.biomarkers)
# project, study, recording, and analysis no longer exist
```

### Score many files at once

```python
result = await client.workflows.analyze_files(
    files=["sub-01.edf", "sub-02.edf", "sub-03.edf"],
    analysis_config_id="u-sleep-research-v1",
)
for ok in result.succeeded:
    print(ok.file, ok.result.biomarkers)
for bad in result.failed:
    print(bad.file, bad.status, bad.error)   # per-file; never aborts the batch
```

### Use the low-level client

Every REST resource is a typed namespace on the client:

```python
from yousleep_common.models import ProjectCreate, StudyCreate, AnalysisRequest

project = await client.projects.create(ProjectCreate(name="My Study 2026"))
study = await client.studies.create(project.id, StudyCreate(name="Subject 001"))
recording = await client.recordings.upload(project.id, study.id, "night.edf")
analysis = await client.analyses.submit(
    project.id, study.id, recording.id,
    AnalysisRequest(analysis_config_id="u-sleep-research-v1"),
)
analysis = await client.analyses.wait_for(
    project.id, study.id, recording.id, analysis.id, timeout=3600
)
events = await client.analyses.get_events(project.id, study.id, recording.id, analysis.id)
```

Available namespaces: `projects`, `studies`, `recordings`, `analyses`,
`batch`, `workflows`, `reports`, `user`, `auth`, `billing`, `status`, `legal`,
`admin`.

## Error handling & usage limits

All SDK errors derive from `YouSleepClientError`:

```python
from yousleep_common.client import (
    AnalysisWorkflowError,   # analysis ended failed/cancelled (carries logs)
    AuthenticationError,     # 401
    InsufficientCreditsError,  # 402 — not enough credits
    NotFoundError,           # 404
    QuotaExceededError,      # usage quota hit (projects/studies/analyses/hours)
    RateLimitError,          # 429 throttling (retried automatically first)
    ValidationError,         # 422
)
```

Quota errors are detected and raised immediately (no pointless retries).
Check your limits and current consumption up front:

```python
limits = await client.user.usage_limits()     # your account's usage limits (None = unlimited)
usage = await client.user.usage_detailed()    # your current usage
print(usage.storage.active, "/", limits.storage.active, "bytes")
```

In multi-file workflows, a quota hit on one file fails only that file's
outcome — the rest of the batch continues.

## Shared models

`yousleep_common.models` and `yousleep_common.types` are the platform's shared
contract — the same Pydantic models and enums used by the YouSleep API server.
Import them for type-safe request building and response handling:

```python
from yousleep_common.models import AnalysisRequest, Event, StudyCreate
from yousleep_common.types import AnalysisStatus, AnalysisType, EventLabel
```

## Documentation

- [SDK guide](docs/docs/sdk-guide.md) — full client tour
- [Workflows guide](docs/docs/sdk-workflows.md) — high-level helpers in depth
- API reference — auto-generated (`make docs-serve`)

## Development

```bash
make install   # uv sync
make check     # ruff, mypy (strict), deptry, lock check
make test      # pytest
make verify-routes  # SDK ↔ OpenAPI spec coverage check
```

Releases are automated with python-semantic-release (Angular commit
convention).

## License

[Apache-2.0](LICENSE).

## Support

- [GitHub Issues](https://github.com/yousleep-ai/common/issues)
- support@yousleep.ai
