Skip to content

analyses

Analysis endpoint handlers.

AnalysesEndpoint

Bases: BaseEndpoint

Handles analysis-related API endpoints.

Analyses are sleep analysis jobs (staging, REM detection, etc.) run on recordings.

cancel(analysis_id) async

Cancel a running or pending analysis.

Parameters:

Name Type Description Default
analysis_id UUID | str

UUID of the analysis to cancel

required

Returns:

Type Description
MessageResponse

Message confirming cancellation

Raises:

Type Description
NotFoundError

If analysis doesn't exist

ValidationError

If analysis cannot be cancelled

AuthenticationError

If not authenticated

count_for_project(project_id, *, status_any=None, analysis_config_id=None) async

Count the analyses a filter resolves to, without fetching them.

This is the expected_count a live-set analysis operation (e.g. a filtered batch delete) must present — the server re-resolves with the SAME predicate and rejects on drift.

delete(analysis_id) async

Delete an analysis and its results.

Parameters:

Name Type Description Default
analysis_id UUID | str

UUID of the analysis to delete

required

Returns:

Type Description
MessageResponse

Message confirming deletion

Raises:

Type Description
NotFoundError

If analysis doesn't exist

AuthenticationError

If not authenticated

download_events_json(analysis_id) async

Download an analysis and its events as one document.

This is the downloadable events file, validated: the analysis as analysis and its events as events. The server records the download in the project's access log.

Parameters:

Name Type Description Default
analysis_id UUID | str

UUID of the analysis

required

Returns:

Type Description
AnnotatedAnalysisEvents

The analysis and its events

Raises:

Type Description
NotFoundError

If analysis doesn't exist

AuthenticationError

If not authenticated

Example
document = await client.analyses.download_events_json(analysis.id)
print(document.analysis.status, len(document.events))

get(analysis_id) async

Get detailed information about an analysis.

Parameters:

Name Type Description Default
analysis_id UUID | str

UUID of the analysis

required

Returns:

Type Description
AnalysisOut

Detailed analysis information

Raises:

Type Description
NotFoundError

If analysis doesn't exist

AuthenticationError

If not authenticated

get_biomarkers(analysis_id, soremp_threshold_min=15.0, statistics_window_start_ms=None, statistics_window_end_ms=None) async

Compute biomarkers for a completed staging analysis.

Returns 13 standard sleep biomarkers (TST, TIB, SE, SOL, WASO, etc.) plus quality metrics. The statistics window defaults to study lights off/on events, then full recording length.

Parameters:

Name Type Description Default
analysis_id UUID | str

UUID of the analysis

required
soremp_threshold_min float

Max minutes from sleep onset to the first REM epoch for a SOREMP

15.0
statistics_window_start_ms int | None

Optional window start override (ms)

None
statistics_window_end_ms int | None

Optional window end override (ms)

None

Returns:

Type Description
AnalysisBiomarkersResponse

AnalysisBiomarkersResponse with biomarkers, QC metrics,

AnalysisBiomarkersResponse

metadata, and the server-defined presentation table

AnalysisBiomarkersResponse

(None when the server predates the field)

Raises:

Type Description
NotFoundError

If analysis doesn't exist

AuthenticationError

If not authenticated

get_config(analysis_config_id, *, expand_licence=False) async

Get detailed information about an analysis configuration.

Parameters:

Name Type Description Default
analysis_config_id str

ID of the analysis configuration

required
expand_licence bool

Return the licence with the licence document's name, validity dates and summary, not only its reference.

False

Returns:

Type Description
AnalysisConfigOut

Detailed analysis configuration information

Raises:

Type Description
NotFoundError

If configuration doesn't exist

AuthenticationError

If not authenticated

Example
config = await client.analyses.get_config("u-sleep-research-v1")
print(f"Name: {config.name}")
print(f"Description: {config.description}")

get_event_blocks(analysis_id) async

Get analysis results as one document of event blocks.

The bulk companion to :meth:get_events. A block is a run of consecutive equal-duration slots with per-slot attributes as parallel arrays, so a full night of 1 Hz sleep staging is a handful of blocks rather than tens of thousands of events. Prefer this whenever you are reading dense output at scale; get_events stays the convenient form for a single analysis you intend to iterate.

The document is returned whole — there is no server-side filtering, so fetch once and slice locally.

Parameters:

Name Type Description Default
analysis_id UUID | str

UUID of the analysis

required

Returns:

Type Description
EventBlocksDocument

The analysis's events in block form.

Raises:

Type Description
NotFoundError

If the analysis doesn't exist or has no results

AuthenticationError

If not authenticated

Example
from yousleep_common.utils.event_blocks import blocks_to_events

document = await client.analyses.get_event_blocks(analysis.id)
print(document.event_count)
events = blocks_to_events(document.blocks)  # if you need them flat

get_events(analysis_id, *, window_start_time_ms=None, window_end_time_ms=None, window_mode=None, label=None, analysis_type=None, match_mode=None, offset=None, limit=None) async

Get analysis results as a list of events.

Called with the analysis id alone, this returns every event. The server can narrow the list in two independent stages:

  1. A time window, given in milliseconds from the start of the recording. window_mode decides how an event must sit in the window to be kept; the server's default is START.
  2. A label filter, which names one label, the labels of one analysis_type, or both. match_mode keeps the matching events (INCLUDE, the default) or removes them (EXCLUDE).

offset and limit page through what the filters leave, in the stored event order.

Parameters:

Name Type Description Default
analysis_id UUID | str

UUID of the analysis

required
window_start_time_ms int | None

Start of the time window

None
window_end_time_ms int | None

End of the time window

None
window_mode WindowFilterModes | None

How an event is matched against the window

None
label EventLabel | None

One event label to match

None
analysis_type AnalysisType | None

Match every label of this analysis type

None
match_mode MatchModes | None

Keep or remove the events the labels match

None
offset int | None

Events to skip, after the filters

None
limit int | None

Maximum events to return

None

Returns:

Type Description
list[Event]

List of events from the analysis

Raises:

Type Description
NotFoundError

If analysis doesn't exist or has no results

ValidationError

If the window is invalid

AuthenticationError

If not authenticated

Example
from yousleep_common.types import AnalysisType

# The staging of the first hour only
events = await client.analyses.get_events(
    analysis.id,
    window_end_time_ms=3_600_000,
    analysis_type=AnalysisType.STAGING,
)

get_logs(analysis_id) async

Get analysis execution logs.

Parameters:

Name Type Description Default
analysis_id UUID | str

UUID of the analysis

required

Returns:

Type Description
AnalysisLogs | None

Analysis logs, or None if no logs are available

Raises:

Type Description
NotFoundError

If analysis doesn't exist

AuthenticationError

If not authenticated

get_run(analysis_id) async

Get where an analysis runs or ran, and on what.

The place is known from submission; the image digest and the inputs' SHA-256 once the run's result is accepted. The runner's name is shown to the organization's owners and admins only.

Parameters:

Name Type Description Default
analysis_id UUID | str

UUID of the analysis

required

Returns:

Type Description
AnalysisRunOut

The analysis's run

Raises:

Type Description
NotFoundError

If analysis doesn't exist

AuthenticationError

If not authenticated

list(recording_id, status=None, analysis_type=None, *, offset=None, limit=None) async

List analyses for a specific recording.

With neither offset nor limit every matching analysis is returned.

Parameters:

Name Type Description Default
recording_id UUID | str

UUID of the recording

required
status AnalysisStatus | None

Optional analysis status to filter by

None
analysis_type AnalysisType | None

Optional analysis type to filter by

None
offset int | None

Analyses to skip

None
limit int | None

Maximum analyses to return (1-500)

None

Returns:

Type Description
list[AnalysisOut]

List of analyses

Raises:

Type Description
NotFoundError

If recording doesn't exist

AuthenticationError

If not authenticated

list_configs(*, expand_licence=False) async

List all available analysis configurations.

Parameters:

Name Type Description Default
expand_licence bool

Return each licence with the licence document's name, validity dates and summary, not only its reference.

False

Returns:

Type Description
list[AnalysisConfigOut]

List of available analysis configurations

Raises:

Type Description
AuthenticationError

If not authenticated

Example
configs = await client.analyses.list_configs()
for config in configs:
    print(f"{config.id}: {config.name}")

list_for_project(project_id, *, status_any=None, analysis_config_id=None, skip=0, limit=100) async

List one page of a project's analyses, newest first.

status_any and analysis_config_id are the analysis selector's filter vocabulary: this listing previews exactly what a live-set batch operation with the same filter will address. An unknown analysis_config_id raises NotFoundError rather than returning an empty page.

Example
failed = await client.analyses.list_for_project(
    project, status_any=[AnalysisStatus.FAILED]
)

list_publications() async

List the publications behind the analyses on offer to the caller.

The evidence of every analysis the caller may run, with the analysis families it is grouped by, as the portal's publications page shows it.

Returns:

Type Description
PublicationListing

The publications and their families.

quote(recording_id, request) async

Quote what an analysis would cost, without submitting it.

The quote runs the same validation and pricing as :meth:submit, so for the same request it equals the charge the submission would settle. It also says which balance pays for it (research analyses from grants, commercial ones from purchased credits) and whether that balance covers it. Nothing is created and no credits are reserved; the submission itself remains the gate.

A request that could not be submitted fails here in the same way, so a quote also checks a request before it is sent.

Parameters:

Name Type Description Default
recording_id UUID | str

UUID of the recording to analyze

required
request AnalysisRequest

The same request you would pass to :meth:submit

required

Returns:

Type Description
BillingQuote

The estimated credits, the current balances and, when the

BillingQuote

submission would be refused, blocked_reason

Raises:

Type Description
ValidationError

If configuration or parameters are invalid

NotFoundError

If recording or configuration doesn't exist

AuthenticationError

If not authenticated

Example
quote = await client.analyses.quote(recording.id, request)
if quote.blocked_reason is None:
    analysis = await client.analyses.submit(recording.id, request)

stream_status(analysis_id, poll_interval=5.0, timeout=None) async

Stream analysis status updates until completion or timeout.

Parameters:

Name Type Description Default
analysis_id UUID | str

UUID of the analysis

required
poll_interval float

Seconds between status checks

5.0
timeout float | None

Maximum total seconds to poll before raising ClientTimeoutError. None = no limit.

None

Yields:

Type Description
AsyncIterator[AnalysisOut]

Analysis status updates

Raises:

Type Description
NotFoundError

If analysis doesn't exist

AuthenticationError

If not authenticated

ClientTimeoutError

If timeout is reached before terminal status

Example
async for status in client.analyses.stream_status(
    analysis_id=analysis.id,
    timeout=3600,  # 1 hour max
):
    print(f"Status: {status.status}, Progress: {status.progress}%")
    if status.status == AnalysisStatus.COMPLETED:
        break

submit(recording_id, request) async

Submit a new analysis job.

Parameters:

Name Type Description Default
recording_id UUID | str

UUID of the recording to analyze

required
request AnalysisRequest

Analysis request with config ID and optional parameters

required

Returns:

Type Description
AnalysisOut

Information about the submitted analysis

Raises:

Type Description
ValidationError

If configuration is invalid

NotFoundError

If recording doesn't exist

AuthenticationError

If not authenticated

Example
from yousleep_common.models import AnalysisRequest

# Submit with config ID
request = AnalysisRequest(
    analysis_config_id="u-sleep-research-v1",
    channels=["EEG Fpz-Cz", "EOG horizontal"],
    parameters=[["data-per-prediction", 3840]]
)
analysis = await client.analyses.submit(
    recording_id=recording.id,
    request=request
)

wait_for(analysis_id, poll_interval=5.0, timeout=None) async

Poll an analysis until it reaches a terminal status and return it.

Convenience wrapper over stream_status for the common case where only the final state matters: it consumes the status stream and returns the last (terminal) AnalysisOut. Terminal statuses are COMPLETED, FAILED, CANCELLED, REJECTED and REVIEW — inspect .status on the return value to distinguish success from failure.

Parameters:

Name Type Description Default
analysis_id UUID | str

UUID of the analysis

required
poll_interval float

Seconds between status checks

5.0
timeout float | None

Maximum total seconds to poll before raising ClientTimeoutError. None = no limit.

None

Returns:

Type Description
AnalysisOut

The analysis in its terminal status.

Raises:

Type Description
NotFoundError

If analysis doesn't exist

AuthenticationError

If not authenticated

ClientTimeoutError

If timeout is reached before a terminal status

Example
analysis = await client.analyses.wait_for(
    analysis_id=analysis.id,
    timeout=3600,
)
if analysis.status == AnalysisStatus.COMPLETED:
    events = await client.analyses.get_events(analysis.id)