Skip to content

Commit

Permalink
Docs: Update for Compute v2.1.0 (#12223)
Browse files Browse the repository at this point in the history
GitOrigin-RevId: aa9d2c6154976ea845b1e2159eae4d1c4d78cb8f
  • Loading branch information
stephencpope authored and Descartes Labs Build committed Oct 4, 2023
1 parent 510bc1d commit 2978701
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 19 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,11 @@ Changelog
`JobStatus.SUCCESS`. If `Job.result()` yields an `None` value, this means that there was no
result (i.e. the execution returned a `None`).

- The `Job.result_blob()` will return the Catalog Storage Blob holding the result, if any.
- The `Job.result_blob()` method will return the Catalog Storage Blob holding the result, if any.

- The `Job.delete()` method will delete any job logs, but will not delete the job result unless
the `delete_results` parameter is supplied.

- The `Function` object now has attributes `namespace` and `owner`.

- The `Function.wait_for_completion()` and new `Function.as_completed()` methods provide a richer
Expand Down
73 changes: 61 additions & 12 deletions descarteslabs/core/compute/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import pkg_resources
from strenum import StrEnum

from descarteslabs.exceptions import ConflictError
from ..client.deprecation import deprecate
from ..client.services.service import ThirdPartyService
from ..common.client import (
Expand Down Expand Up @@ -257,6 +258,9 @@ def __init__(
this limit.
retry_count : int, optional
Number of times to retry a job if it fails.
client : ComputeClient, optional
If set, operations on the function will be performed using the configured client.
Otherwise, the default client will be used.
Examples
--------
Expand Down Expand Up @@ -319,7 +323,7 @@ def __init__(
def __call__(self, *args, tags: List[str] = None, **kwargs):
"""Execute the function with the given arguments.
This call will return a long running job that can be used to monitor the state
This call will return a Job object that can be used to monitor the state
of the job.
Returns
Expand All @@ -329,8 +333,12 @@ def __call__(self, *args, tags: List[str] = None, **kwargs):
Parameters
----------
args : Any, optional
Positional arguments to pass to the function.
tags : List[str], optional
A list of tags to apply to the Job.
kwargs : Any, optional
Keyword arguments to pass to the function.
"""
self.save()
job = Job(function_id=self.id, args=args, kwargs=kwargs, tags=tags)
Expand Down Expand Up @@ -734,7 +742,7 @@ def get(cls, id: str, client: ComputeClient = None, **params):
----------
id : str
Id of function to get.
client: ComputeClient, None
client: ComputeClient, optional
If set, the result will be retrieved using the configured client.
Otherwise, the default client will be used.
include : List[str], optional
Expand Down Expand Up @@ -765,7 +773,7 @@ def list(
----------
page_size : int, default=100
Maximum number of results per page.
client: ComputeClient, None
client: ComputeClient, optional
If set, the result will be retrieved using the configured client.
Otherwise, the default client will be used.
include : List[str], optional
Expand All @@ -789,6 +797,12 @@ def search(cls, client: ComputeClient = None) -> Search["Function"]:
The search is lazy and will be executed when the search is iterated over or
:py:meth:`Search.collect` is called.
Parameters
----------
client: ComputeClient, optional
If set, the result will be retrieved using the configured client.
Otherwise, the default client will be used.
Example
-------
>>> from descarteslabs.compute import Function, FunctionStatus
Expand Down Expand Up @@ -816,13 +830,20 @@ def update_credentials(cls, client: ComputeClient = None):
Notes
-----
Credentials are automatically updated when a new Function is created.
Parameters
----------
client: ComputeClient, optional
If set, the operation will be performed using the configured client.
Otherwise, the default client will be used.
"""
client = client or ComputeClient.get_default_client()
client.set_credentials()

@property
def jobs(self) -> JobSearch:
"""Returns all the Jobs for the Function."""
"""Returns a JobSearch for all the Jobs for the Function."""
if self.state != DocumentState.SAVED:
raise ValueError(
"Cannot search for jobs for a Function that has not been saved"
Expand All @@ -842,25 +863,33 @@ def build_log(self):
return gzip.decompress(response.content).decode()

def delete(self):
"""Deletes the Function and all associated Jobs."""
"""Deletes the Function and all associated Jobs.
If any jobs are in a running state, the deletion will fail.
"""
if self.state == DocumentState.NEW:
raise ValueError("Cannot delete a Function that has not been saved")

for job in self.jobs:
job.delete()
try:
job.delete()
except ConflictError:
pass

self._client.session.delete(f"/functions/{self.id}")
self._deleted = True

def disable(self):
"""Disables the Function so that new jobs cannot be submitted."""
self.enabled = False
self.save()
if self.state != DocumentState.NEW:
self.save()

def enable(self):
"""Enables the Function so that new jobs may be submitted."""
self.enabled = True
self.save()
if self.state != DocumentState.NEW:
self.save()

def save(self):
"""Creates the Function if it does not already exist.
Expand Down Expand Up @@ -1095,7 +1124,7 @@ def delete_jobs(
"""
if self.state != DocumentState.SAVED:
raise ValueError(
"Cannot cancel jobs for a Function that has not been saved"
"Cannot delete jobs for a Function that has not been saved"
)

if query is None:
Expand All @@ -1108,7 +1137,16 @@ def delete_jobs(
return query.delete()

def refresh(self, includes: Optional[str] = None):
"""Updates the Function instance with data from the server."""
"""Updates the Function instance with data from the server.
Parameters
----------
includes : Optional[str], optional
List of additional attributes to include in the response.
Allowed values are:
- "job.statistics": Include statistics about the Job statuses for this Function.
"""
if self.state == DocumentState.NEW:
raise ValueError("Cannot refresh a Function that has not been saved")

Expand All @@ -1123,7 +1161,13 @@ def refresh(self, includes: Optional[str] = None):
self._load_from_remote(response.json())

def iter_results(self, cast_type: Type[Serializable] = None):
"""Iterates over all successful job results."""
"""Iterates over all successful job results.
Parameters
----------
cast_type : Type[Serializable], optional
If set, the results will be cast to the given type.
"""
if self.state != DocumentState.SAVED:
raise ValueError(
"Cannot retrieve results for a Function that has not been saved"
Expand All @@ -1138,8 +1182,13 @@ def results(self, cast_type: Type[Serializable] = None):
Notes
-----
This immediately downloads all results into a list and could run out of memory.
If the result set is large, strongly consider using :py:meth:`Function.refresh`
If the result set is large, strongly consider using :py:meth:`Function.iter_results`
instead.
Parameters
----------
cast_type : Type[Serializable], optional
If set, the results will be cast to the given type.
"""
return list(self.iter_results(cast_type=cast_type))

Expand Down
32 changes: 26 additions & 6 deletions descarteslabs/core/compute/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ def get(cls, id, client: ComputeClient = None, **params) -> "Job":
----------
id : str
The id of the Job to fetch.
client: ComputeClient, None
client: ComputeClient, optional
If set, the result will be retrieved using the configured client.
Otherwise, the default client will be used.
include : List[str], optional
Expand All @@ -252,7 +252,9 @@ def get(cls, id, client: ComputeClient = None, **params) -> "Job":
return cls(**response.json(), client=client, saved=True)

@classmethod
def list(cls, page_size: int = 100, **params) -> JobSearch:
def list(
cls, page_size: int = 100, client: ComputeClient = None, **params
) -> JobSearch:
"""Retrieves an iterable of all jobs matching the given parameters.
If you would like to filter Jobs, use :py:meth:`Job.search`.
Expand All @@ -261,6 +263,9 @@ def list(cls, page_size: int = 100, **params) -> JobSearch:
----------
page_size : int, default=100
Maximum number of results per page.
client: ComputeClient, optional
If set, the result will be retrieved using the configured client.
Otherwise, the default client will be used.
Example
-------
Expand All @@ -269,7 +274,7 @@ def list(cls, page_size: int = 100, **params) -> JobSearch:
[Job <job-id1>: pending, Job <job-id2>: pending, Job <job-id3>: pending]
"""
params = {"page_size": page_size, **params}
search = Job.search().param(**params)
search = Job.search(client=client).param(**params)

# Deprecation: remove this in a future release
if "function_id" in params or "status" in params:
Expand Down Expand Up @@ -325,7 +330,14 @@ def delete(self, delete_result: bool = False):
self._deleted = True

def refresh(self, client: ComputeClient = None) -> None:
"""Update the Job instance with the latest information from the server."""
"""Update the Job instance with the latest information from the server.
Parameters
----------
client: ComputeClient, optional
If set, the result will be retrieved using the configured client.
Otherwise, the default client will be used.
"""
if self.pull_time or self.provisioning_time:
params = {"include": ["timings"]}
else:
Expand All @@ -346,8 +358,8 @@ def result(
cast_type: Type[Serializable], None
If set, the result will be deserialized to the given type.
catalog_client: CatalogClient, None
If set, the result will be retrieved using the configured client.
Otherwise, the default client will be used.
If set, the result will be retrieved using the configured catalog client.
Otherwise, the default catalog client will be used.
Raises
------
Expand Down Expand Up @@ -452,6 +464,12 @@ def search(cls, client: ComputeClient = None) -> JobSearch:
The search is lazy and will be executed when the search is iterated over or
:py:meth:`Search.collect` is called.
Parameters
----------
client: ComputeClient, optional
If set, the result will be retrieved using the configured client.
Otherwise, the default client will be used.
Example
-------
>>> from descarteslabs.compute import Job, JobStatus
Expand Down Expand Up @@ -536,6 +554,8 @@ def iter_log(self, timestamps: bool = True):
def log(self, timestamps: bool = True):
"""Retrieves the log for the job, returning a string.
As logs can potentially be unbounded, consider using :py:meth:`Job.iter_log`.
Parameters
----------
timestamps : bool, True
Expand Down
3 changes: 3 additions & 0 deletions descarteslabs/core/compute/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@


class Serializable:
"""Interface for serializing objects to bytes as
a result of a Function invocation."""

def serialize(self) -> bytes:
raise NotImplementedError()

Expand Down

0 comments on commit 2978701

Please sign in to comment.