From 2bd98078da6974f723b67d20ca422a1d91421178 Mon Sep 17 00:00:00 2001 From: Sam Minot Date: Thu, 3 Sep 2026 20:20:57 -0700 Subject: [PATCH 1/3] Expose dataset compute cost in the SDK Add ExecutionService.get_cost, wrapping the existing /projects/{project}/execution/{dataset}/cost endpoint, and a DataPortalDataset.cost property over it. Co-Authored-By: Claude Opus 5 --- cirro/sdk/dataset.py | 23 ++++++++++++++++++++++- cirro/services/execution.py | 24 ++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/cirro/sdk/dataset.py b/cirro/sdk/dataset.py index cdb95ae..822a8dd 100644 --- a/cirro/sdk/dataset.py +++ b/cirro/sdk/dataset.py @@ -7,7 +7,8 @@ from cirro_api_client.v1.api.processes import validate_file_requirements from cirro_api_client.v1.errors import CirroException, UnexpectedStatus from cirro_api_client.v1.models import Dataset, DatasetDetail, RunAnalysisRequest, ProcessDetail, \ - Status, RunAnalysisRequestParams, Tag, ArtifactType, NamedItem, ValidateFileRequirementsRequest + Status, RunAnalysisRequestParams, Tag, ArtifactType, NamedItem, ValidateFileRequirementsRequest, \ + CostResponse from cirro.cirro_client import CirroApi from cirro.config import Constants @@ -265,6 +266,26 @@ def created_at(self) -> datetime.datetime: """Timestamp of dataset creation""" return self._data.created_at + @property + def cost(self) -> Optional[CostResponse]: + """ + Compute cost of the analysis which produced this dataset, as a + `cirro_api_client.v1.models.CostResponse` -- `total_cost` alongside a + breakdown by task (`tasks`) and by task status group (`groups`). + + Not cached: the cost of a running analysis grows as tasks complete, and + `is_estimate` stays True until the cloud provider reports settled + billing data, so each access re-fetches. + + Returns: + `cirro_api_client.v1.models.CostResponse`, or ``None`` for datasets + which were uploaded rather than produced by an analysis. + """ + return self._client.execution.get_cost( + project_id=self.project_id, + dataset_id=self.id + ) + @cached_property def logs(self) -> str: """ diff --git a/cirro/services/execution.py b/cirro/services/execution.py index 6862ee3..f028ef4 100644 --- a/cirro/services/execution.py +++ b/cirro/services/execution.py @@ -1,9 +1,10 @@ from typing import List, Optional, Dict from cirro_api_client.v1.api.execution import run_analysis, stop_analysis, get_project_summary, \ - get_tasks_for_execution, get_task_logs, get_execution_logs, get_task, get_task_files + get_tasks_for_execution, get_task_logs, get_execution_logs, get_task, get_task_files, calculate_cost from cirro_api_client.v1.api.processes import get_process_parameters -from cirro_api_client.v1.models import RunAnalysisRequest, CreateResponse, Task, GetTaskFilesResponse +from cirro_api_client.v1.models import RunAnalysisRequest, CreateResponse, Task, GetTaskFilesResponse, \ + CostResponse from cirro.models.form_specification import ParameterSpecification from cirro.services.base import BaseService @@ -194,3 +195,22 @@ def get_task_files(self, project_id: str, dataset_id: str, task_id: str) -> Opti task_id=task_id, client=self._api_client ) + + def get_cost(self, project_id: str, dataset_id: str) -> Optional[CostResponse]: + """ + Gets the compute cost of the analysis which produced a dataset, + broken down by task and by task status group. + + While the analysis is running, and for a period afterwards until the + cloud provider reports settled billing data, the returned + `cirro_api_client.v1.models.CostResponse` has `is_estimate` set to True. + + Args: + project_id (str): ID of the Project + dataset_id (str): ID of the Dataset + """ + return calculate_cost.sync( + project_id=project_id, + dataset_id=dataset_id, + client=self._api_client + ) From 2b17cee4cddce72b3035b07c6033354fb2093f02 Mon Sep 17 00:00:00 2001 From: Sam Minot Date: Fri, 4 Sep 2026 05:54:33 -0700 Subject: [PATCH 2/3] Bump version to 1.13.1 Co-Authored-By: Claude Opus 5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 658a114..845d74d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "cirro" -version = "1.13.0" +version = "1.13.1" description = "CLI tool and SDK for interacting with the Cirro platform" authors = ["Cirro Bio "] license = "MIT" From 3f9ca5e81ee38dee46748119e4a7f4438bb7c3de Mon Sep 17 00:00:00 2001 From: Sam Minot Date: Fri, 4 Sep 2026 08:21:38 -0700 Subject: [PATCH 3/3] Correct the is_estimate description in the cost docstrings Co-Authored-By: Claude Opus 5 --- cirro/sdk/dataset.py | 8 ++++---- cirro/services/execution.py | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/cirro/sdk/dataset.py b/cirro/sdk/dataset.py index 822a8dd..8bcb753 100644 --- a/cirro/sdk/dataset.py +++ b/cirro/sdk/dataset.py @@ -271,11 +271,11 @@ def cost(self) -> Optional[CostResponse]: """ Compute cost of the analysis which produced this dataset, as a `cirro_api_client.v1.models.CostResponse` -- `total_cost` alongside a - breakdown by task (`tasks`) and by task status group (`groups`). + breakdown by task (`tasks`) and by task status group (`groups`), plus an + `is_estimate` flag for whether the figure is estimated or measured. - Not cached: the cost of a running analysis grows as tasks complete, and - `is_estimate` stays True until the cloud provider reports settled - billing data, so each access re-fetches. + Not cached: the cost of a running analysis grows as tasks complete, so + each access re-fetches. Returns: `cirro_api_client.v1.models.CostResponse`, or ``None`` for datasets diff --git a/cirro/services/execution.py b/cirro/services/execution.py index f028ef4..6c4da41 100644 --- a/cirro/services/execution.py +++ b/cirro/services/execution.py @@ -201,9 +201,8 @@ def get_cost(self, project_id: str, dataset_id: str) -> Optional[CostResponse]: Gets the compute cost of the analysis which produced a dataset, broken down by task and by task status group. - While the analysis is running, and for a period afterwards until the - cloud provider reports settled billing data, the returned - `cirro_api_client.v1.models.CostResponse` has `is_estimate` set to True. + The returned `cirro_api_client.v1.models.CostResponse` carries an + `is_estimate` flag for whether the figure is estimated or measured. Args: project_id (str): ID of the Project