From 102869c5de3c7d1d19ed40e3bb77ec78b7c727b0 Mon Sep 17 00:00:00 2001 From: Marjorie Lucas <47004511+marjo-luc@users.noreply.github.com> Date: Tue, 3 Sep 2024 17:02:35 -0700 Subject: [PATCH] added more query params (#98) * added more query params * added get_job_details flag * cleanup * Update maap/maap.py Co-authored-by: Chuck Daniels * Update maap/maap.py Co-authored-by: Chuck Daniels * Update maap/maap.py Co-authored-by: Chuck Daniels * added docstring | updated param handling * review updates * review updates * renamed file --------- Co-authored-by: Chuck Daniels --- maap/maap.py | 80 ++++++++++++++++++++++++++++++++++++++++++++--- maap/utils/job.py | 21 +++++++++++++ 2 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 maap/utils/job.py diff --git a/maap/maap.py b/maap/maap.py index 8b91695..7b2858d 100644 --- a/maap/maap.py +++ b/maap/maap.py @@ -19,6 +19,7 @@ from maap.AWS import AWS from maap.dps.DpsHelper import DpsHelper from maap.utils import endpoints +from maap.utils import job logger = logging.getLogger(__name__) @@ -256,13 +257,84 @@ def cancelJob(self, jobid): job.id = jobid return job.cancel_job() - def listJobs(self, username=None, page_size=None, offset=None): - if username==None and self.profile is not None and 'username' in self.profile.account_info().keys(): + def listJobs(self, username=None, *, + algo_id=None, + end_time=None, + get_job_details=True, + offset=0, + page_size=10, + queue=None, + start_time=None, + status=None, + tag=None, + version=None): + """ + Returns a list of jobs for a given user that matches query params provided. + + Args: + username (str, optional): Platform user. If no username is provided, the profile username will be used. + algo_id (str, optional): Algorithm type. + end_time (str, optional): Specifying this parameter will return all jobs that have completed from the provided end time to now. e.g. 2024-01-01 or 2024-01-01T00:00:00.000000Z. + get_job_details (bool, optional): Flag that determines whether to return a detailed job list or a compact list containing just the job ids and their associated job tags. Default is True. + offset (int, optional): Offset for pagination. Default is 0. + page_size (int, optional): Page size for pagination. Default is 10. + queue (str, optional): Job processing resource. + start_time (str, optional): Specifying this parameter will return all jobs that have started from the provided start time to now. e.g. 2024-01-01 or 2024-01-01T00:00:00.000000Z. + status (str, optional): Job status, e.g. job-completed, job-failed, job-started, job-queued. + tag (str, optional): User job tag/identifier. + version (str, optional): Algorithm version, e.g. GitHub branch or tag. + + Returns: + list: List of jobs for a given user that matches query params provided. + + Raises: + ValueError: If username is not provided and cannot be obtained from the user's profile. + ValueError: If either algo_id or version is provided, but not both. + """ + if username is None and self.profile is not None and 'username' in self.profile.account_info().keys(): username = self.profile.account_info()['username'] - url = os.path.join(self.config.dps_job, username, endpoints.DPS_JOB_LIST) - params = {k: v for k, v in (("page_size", page_size), ("offset", offset)) if v} + if username is None: + raise ValueError("Unable to determine username from profile. Please provide a username.") + + url = "/".join( + segment.strip("/") + for segment in (self.config.dps_job, username, endpoints.DPS_JOB_LIST) + ) + + params = { + k: v + for k, v in ( + ("algo_id", algo_id), + ("end_time", end_time), + ("get_job_details", get_job_details), + ("offset", offset), + ("page_size", page_size), + ("queue", queue), + ("start_time", start_time), + ("status", status), + ("tag", tag), + ("username", username), + ("version", version), + ) + if v is not None + } + if (not algo_id) != (not version): + # Either algo_id or version was supplied as a non-empty string, but not both. + # Either both must be non-empty strings or both must be None. + raise ValueError("Either supply non-empty strings for both algo_id and version, or supply neither.") + + # DPS requests use 'job_type', which is a concatenation of 'algo_id' and 'version' + if algo_id and version: + params['job_type'] = f"{algo_id}:{version}" + + algo_id = params.pop('algo_id', None) + version = params.pop('version', None) + + if status is not None: + params['status'] = job.validate_job_status(status) + headers = self._get_api_header() logger.debug('GET request sent to {}'.format(url)) logger.debug('headers:') diff --git a/maap/utils/job.py b/maap/utils/job.py new file mode 100644 index 0000000..549d5e1 --- /dev/null +++ b/maap/utils/job.py @@ -0,0 +1,21 @@ +# Valid job statuses (loosely based on OGC job status types) +JOB_STATUSES = {'Accepted', 'Running', 'Succeeded', 'Failed', 'Dismissed', 'Deduped', 'Offline'} + +def validate_job_status(status): + ''' + Validates job status + + Args: + status (str): Job status. Accepted values are: 'Accepted', 'Running', 'Succeeded', 'Failed, 'Dismissed', 'Deduped', and 'Offline'. + + Returns: + status (str): Returns unmodified job status if job status is valid. + + Raises: + ValueError: If invalid job status is provided. + ''' + if status not in JOB_STATUSES: + valid_statuses = ", ".join(str(status) for status in JOB_STATUSES) + raise ValueError("Invalid job status: '{}'. Job status must be one of the following: {}".format(status, valid_statuses)) + + return status \ No newline at end of file