sutro 0.1.23__tar.gz → 0.1.25__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sutro might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sutro
3
- Version: 0.1.23
3
+ Version: 0.1.25
4
4
  Summary: Sutro Python SDK
5
5
  Project-URL: Homepage, https://sutro.sh
6
6
  Project-URL: Documentation, https://docs.sutro.sh
@@ -9,7 +9,7 @@ installer = "uv"
9
9
 
10
10
  [project]
11
11
  name = "sutro"
12
- version = "0.1.23"
12
+ version = "0.1.25"
13
13
  description = "Sutro Python SDK"
14
14
  readme = "README.md"
15
15
  requires-python = ">=3.10"
@@ -215,7 +215,7 @@ class Sutro:
215
215
  json_schema: Dict[str, Any],
216
216
  sampling_params: dict,
217
217
  system_prompt: str,
218
- dry_run: bool,
218
+ cost_estimate: bool,
219
219
  stay_attached: Optional[bool],
220
220
  random_seed_per_input: bool,
221
221
  truncate_rows: bool
@@ -232,7 +232,7 @@ class Sutro:
232
232
  "job_priority": job_priority,
233
233
  "json_schema": json_schema,
234
234
  "system_prompt": system_prompt,
235
- "dry_run": dry_run,
235
+ "cost_estimate": cost_estimate,
236
236
  "sampling_params": sampling_params,
237
237
  "random_seed_per_input": random_seed_per_input,
238
238
  "truncate_rows": truncate_rows
@@ -245,7 +245,7 @@ class Sutro:
245
245
  # Terminal size {self._terminal_width} is too small to display spinner with the given settings.
246
246
  # https://github.com/pavdmyt/yaspin/blob/9c7430b499ab4611888ece39783a870e4a05fa45/yaspin/core.py#L568-L571
247
247
  job_id = None
248
- t = f"Creating {'[dry run] ' if dry_run else ''}priority {job_priority} job"
248
+ t = f"Creating {'[cost estimate] ' if cost_estimate else ''}priority {job_priority} job"
249
249
  spinner_text = to_colored_text(t)
250
250
  try:
251
251
  with yaspin(SPINNER, text=spinner_text, color=YASPIN_COLOR) as spinner:
@@ -262,12 +262,12 @@ class Sutro:
262
262
  return None
263
263
  else:
264
264
  job_id = response_data["results"]
265
- if dry_run:
265
+ if cost_estimate:
266
266
  spinner.write(
267
- to_colored_text(f"Awaiting cost estimates with job ID: {job_id}. You can safely detach and retrieve the cost estimates later.", state="info")
267
+ to_colored_text(f"Awaiting cost estimates with job ID: {job_id}. You can safely detach and retrieve the cost estimates later.")
268
268
  )
269
269
  spinner.stop()
270
- self.await_job_completion(job_id, obtain_results=False)
270
+ self.await_job_completion(job_id, obtain_results=False, is_cost_estimate=True)
271
271
  cost_estimate = self._get_job_cost_estimate(job_id)
272
272
  spinner.write(
273
273
  to_colored_text(f"✔ Cost estimates retrieved for job {job_id}: ${cost_estimate}", state="success")
@@ -410,7 +410,7 @@ class Sutro:
410
410
  spinner.stop()
411
411
  return None
412
412
 
413
- results = job_results_response.json()["results"]
413
+ results = job_results_response.json()["results"]["outputs"]
414
414
 
415
415
  spinner.write(
416
416
  to_colored_text(
@@ -421,12 +421,6 @@ class Sutro:
421
421
  spinner.stop()
422
422
 
423
423
  if isinstance(data, (pd.DataFrame, pl.DataFrame)):
424
- sample_n = 1 if sampling_params is None else sampling_params["n"]
425
- if sample_n > 1:
426
- results = [
427
- results[i : i + sample_n]
428
- for i in range(0, len(results), sample_n)
429
- ]
430
424
  if isinstance(data, pd.DataFrame):
431
425
  data[output_column] = results
432
426
  elif isinstance(data, pl.DataFrame):
@@ -538,20 +532,8 @@ class Sutro:
538
532
  text=to_colored_text("Looking for job..."),
539
533
  color=YASPIN_COLOR,
540
534
  ) as spinner:
541
- # Get job information from list-jobs endpoint
542
- # TODO(cooper) we should add a get jobs endpoint:
543
- # GET /jobs/{job_id}
544
- jobs_response = s.get(
545
- f"{self.base_url}/list-jobs",
546
- headers=headers
547
- )
548
- jobs_response.raise_for_status()
549
-
550
- # Find the specific job we want to attach to
551
- job = next(
552
- (job for job in jobs_response.json()["jobs"] if job["job_id"] == job_id),
553
- None
554
- )
535
+ # Fetch the specific job we want to attach to
536
+ job = self._fetch_job(job_id)
555
537
 
556
538
  if not job:
557
539
  spinner.write(to_colored_text(f"Job {job_id} not found", state="fail"))
@@ -732,7 +714,7 @@ class Sutro:
732
714
  """
733
715
  Helper function to list jobs.
734
716
  """
735
- endpoint = f"{self.base_url}/list-jobs"
717
+ endpoint = f"{self.base_url}/list-jobs˚"
736
718
  headers = {
737
719
  "Authorization": f"Key {self.api_key}",
738
720
  "Content-Type": "application/json",
@@ -742,25 +724,38 @@ class Sutro:
742
724
  return None
743
725
  return response.json()["jobs"]
744
726
 
727
+ def _fetch_job(self, job_id):
728
+ """
729
+ Helper function to fetch a single job.
730
+ """
731
+ endpoint = f"{self.base_url}/jobs/{job_id}"
732
+ headers = {
733
+ "Authorization": f"Key {self.api_key}",
734
+ "Content-Type": "application/json",
735
+ }
736
+ response = requests.get(endpoint, headers=headers)
737
+ if response.status_code != 200:
738
+ return None
739
+ return response.json().get('job')
740
+
745
741
  def _get_job_cost_estimate(self, job_id: str):
746
742
  """
747
743
  Get the cost estimate for a job.
748
744
  """
749
- all_jobs = self._list_jobs_helper()
750
- for job in all_jobs:
751
- if job["job_id"] == job_id:
752
- return job["cost_estimate"]
753
- return None
745
+ job = self._fetch_job(job_id)
746
+ if not job:
747
+ return None
748
+
749
+ return job.get('cost_estimate')
754
750
 
755
751
  def _get_failure_reason(self, job_id: str):
756
752
  """
757
753
  Get the failure reason for a job.
758
754
  """
759
- all_jobs = self._list_jobs_helper()
760
- for job in all_jobs:
761
- if job["job_id"] == job_id:
762
- return job["failure_reason"]
763
- return None
755
+ job = self._fetch_job(job_id)
756
+ if not job:
757
+ return None
758
+ return job.get('failure_reason')
764
759
 
765
760
  def _fetch_job_status(self, job_id: str):
766
761
  """
@@ -1245,7 +1240,7 @@ class Sutro:
1245
1240
  return
1246
1241
  return response.json()["quotas"]
1247
1242
 
1248
- def await_job_completion(self, job_id: str, timeout: Optional[int] = 7200, obtain_results: bool = True) -> list | None:
1243
+ def await_job_completion(self, job_id: str, timeout: Optional[int] = 7200, obtain_results: bool = True, is_cost_estimate: bool=False) -> list | None:
1249
1244
  """
1250
1245
  Waits for job completion to occur and then returns the results upon
1251
1246
  a successful completion.
@@ -1266,8 +1261,9 @@ class Sutro:
1266
1261
  with yaspin(
1267
1262
  SPINNER, text=to_colored_text("Awaiting job completion"), color=YASPIN_COLOR
1268
1263
  ) as spinner:
1269
- clickable_link = make_clickable_link(f'https://app.sutro.sh/jobs/{job_id}')
1270
- spinner.write(to_colored_text(f'Progress can also be monitored at: {clickable_link}'))
1264
+ if not is_cost_estimate:
1265
+ clickable_link = make_clickable_link(f'https://app.sutro.sh/jobs/{job_id}')
1266
+ spinner.write(to_colored_text(f'Progress can also be monitored at: {clickable_link}'))
1271
1267
  while (time.time() - start_time) < timeout:
1272
1268
  try:
1273
1269
  status = self._fetch_job_status(job_id)
@@ -1284,9 +1280,9 @@ class Sutro:
1284
1280
  spinner.text = to_colored_text(f"Job status is {status} for {job_id}")
1285
1281
 
1286
1282
  if status == JobStatus.SUCCEEDED:
1287
- spinner.write(to_colored_text("Job completed! Retrieving results...", "success"))
1288
1283
  spinner.stop() # Stop this spinner as `get_job_results` has its own spinner text
1289
1284
  if obtain_results:
1285
+ spinner.write(to_colored_text("Job completed! Retrieving results...", "success"))
1290
1286
  results = self.get_job_results(job_id)
1291
1287
  break
1292
1288
  if status == JobStatus.FAILED:
File without changes
File without changes
File without changes
File without changes
File without changes