From 888fb073e4337fc2a142566fc01ff99e0add1e22 Mon Sep 17 00:00:00 2001 From: Kamsiy Date: Wed, 17 Jul 2019 15:13:43 -0500 Subject: [PATCH 1/7] Create login and logout feature for python api --- .gitignore | 1 + Python/api/__init__.py | 0 Python/api/boa_client.py | 55 ++++++++++++++++++++++++++++++++++++++++ Python/api/exceptions.py | 6 +++++ Python/api/util.py | 26 +++++++++++++++++++ 5 files changed, 88 insertions(+) create mode 100644 Python/api/__init__.py create mode 100644 Python/api/boa_client.py create mode 100644 Python/api/exceptions.py create mode 100644 Python/api/util.py diff --git a/.gitignore b/.gitignore index 8ee9e7b..358152c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ **/obj/** **/*.suo **/*.userprefs +**/__pycache__ \ No newline at end of file diff --git a/Python/api/__init__.py b/Python/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Python/api/boa_client.py b/Python/api/boa_client.py new file mode 100644 index 0000000..4fb0dde --- /dev/null +++ b/Python/api/boa_client.py @@ -0,0 +1,55 @@ +import xmlrpc.client +import exceptions +import util + +BOA_PROXY = "http://boa.cs.iastate.edu/boa/?q=boa/api" + +class BoaClient(object): + """ A client class for accessing boa's api + + Attributes: + server (:obj: `ServerProxy`): + trans (:obj: `Transport`) + """ + + def __init__(self): + """Create a new Boa API client, using the standard domain/path.""" + self.trans = util.CookiesTransport() + self.__logged_in = False + self.server = xmlrpc.client.ServerProxy(BOA_PROXY, transport=self.trans) + + def login(self, username, password): + """log into the boa framework using the remote api + + Args: + username: username for boa account + password: password for boa account + """ + self.__logged_in = True + response = self.server.user.login(username, password) + self.trans.add_csrf(response["token"]) + return response + + def close(self): + """Log out of the boa framework using the remote api""" + self.ensure_logged_in() + self.server.user.logout() + self.__logged_in = False + + def ensure_logged_in(self): + """Checks if a user is currently logged in through the remote api + + Raises: + NotLoggedInException: if user is not currently logged in + """ + if not self.__logged_in: + raise NotLoggedInException("User not currently logged in") + + def datasets(self): + """ Retrieves datasetsets currently provided by boa + + Returns: + a list of boa datasets + """ + self.ensure_logged_in() + return self.server.boa.datasets() \ No newline at end of file diff --git a/Python/api/exceptions.py b/Python/api/exceptions.py new file mode 100644 index 0000000..4e1cb7a --- /dev/null +++ b/Python/api/exceptions.py @@ -0,0 +1,6 @@ +class NotLoggedInException(Exception): + pass + + +class BoaException(Exception): + pass \ No newline at end of file diff --git a/Python/api/util.py b/Python/api/util.py new file mode 100644 index 0000000..1c1503e --- /dev/null +++ b/Python/api/util.py @@ -0,0 +1,26 @@ +import xmlrpc + +class CookiesTransport(xmlrpc.client.Transport): + """A Transport subclass that retains cookies over its lifetime.""" + + def __init__(self): + super().__init__() + self._cookies = [] + self._csrf = [] + + def add_csrf(self, token): + self._csrf.append(token) + + def send_headers(self, connection, headers): + if self._cookies: + connection.putheader("Cookie", "; ".join(self._cookies)) + connection.putheader("X-CSRF-Token", "; ".join(self._csrf)) + super().send_headers(connection, headers) + + def parse_response(self, response): + session_message = response.msg.get_all("Set-Cookie") + if session_message is not None: + for header in response.msg.get_all("Set-Cookie"): + cookie = header.split(";", 1)[0] + self._cookies.append(cookie) + return super().parse_response(response) \ No newline at end of file From a966bf12c3a3d3bb0e48910986f27de33d530978 Mon Sep 17 00:00:00 2001 From: Kamsiy Date: Mon, 22 Jul 2019 14:31:30 -0500 Subject: [PATCH 2/7] Add means for handling boa jobs --- Python/api/boa_client.py | 114 ++++++++++++++++++++++++++++++++++++--- Python/api/job_handle.py | 25 +++++++++ Python/api/util.py | 6 ++- 3 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 Python/api/job_handle.py diff --git a/Python/api/boa_client.py b/Python/api/boa_client.py index 4fb0dde..28a8610 100644 --- a/Python/api/boa_client.py +++ b/Python/api/boa_client.py @@ -8,8 +8,8 @@ class BoaClient(object): """ A client class for accessing boa's api Attributes: - server (:obj: `ServerProxy`): - trans (:obj: `Transport`) + server (xmlrpc.client.ServerProxy): + trans (xmlrpc.client.Transport) """ def __init__(self): @@ -22,8 +22,8 @@ def login(self, username, password): """log into the boa framework using the remote api Args: - username: username for boa account - password: password for boa account + username (str): username for boa account + password (str): password for boa account """ self.__logged_in = True response = self.server.user.login(username, password) @@ -39,6 +39,9 @@ def close(self): def ensure_logged_in(self): """Checks if a user is currently logged in through the remote api + Returns: + bool: True if user is logged in, false if otherwise + Raises: NotLoggedInException: if user is not currently logged in """ @@ -49,7 +52,106 @@ def datasets(self): """ Retrieves datasetsets currently provided by boa Returns: - a list of boa datasets + list: a list of boa datasets + """ + self.ensure_logged_in() + return self.server.boa.datasets() + + def dataset_names(self): + """Retrieves a list of names of all datasets provided by boa + + Returns: + list: the dataset names + """ + self.ensure_logged_in() + dataset_names = [] + datasets = self.datasets() + for x in datasets: + dataset_names.append(x['name']) + return dataset_names + + def get_dataset(self, name): + """Retrieves a dataset given a name. + + Args: + name (str): The name of the input dataset to return. + + Returns: + dict: a dictionary with the keys id and name + """ + self.ensure_logged_in() + for x in self.datasets(): + if x['name'] == name: + return x + return None + + def last_job(self): + """Retrieves the most recently submitted job + + Returns: + JobHandle: the last submitted job + """ + self.ensure_logged_in() + jobs = self.job_list(False, 0, 1) + return jobs[0] + + def job_count(self, pub_only=False): + """Retrieves the number of jobs submitted by a user + + Args: + pub_only (bool, optional): if true, return only public jobs + otherwise return all jobs + + Returns: + int: the number of jobs submitted by a user + """ + self.ensure_logged_in() + return self.server.boa.count(pub_only) + + def query(self, query, dataset=None): + """Submits a new query to Boa to query the specified and returns a handle to the new job. + + Args: + query (str): a boa query represented as a string. + dataset (str, optional): the name of the input dataset. + + Returns: + (JobHandle) a job + """ + self.ensure_logged_in() + id = 0 if dataset is None else dataset.get_id() + job = self.server.boa.submit(query, self.get_datasets()[id]['id']) + return parse_job(self, job) + + def get_job(self, id): + """Retrieves a job given an id. + + Args: + id (int): the id of the job you want to retrieve + + Returns: + JobHandle: the desired job. + """ + self.ensure_logged_in() + return parse_job(self.server, self.server.boa.job(id)) + + def job_list(self, pub_only=False, offset=0, length=1000): + """Returns a list of the most recent jobs, based on an offset and length. + + This includes public and private jobs. Returned jobs are ordered from newest to oldest + + Args: + pub_only (bool, optional): if true, only return public jobs otherwise return all jobs + offset (int, optional): the starting offset + length (int, optional): the number of jobs (at most) to return + + Returns: + list: a list of jobs where each element is a jobHandle """ self.ensure_logged_in() - return self.server.boa.datasets() \ No newline at end of file + list = self.server.boa.jobs(pub_only, offset, length) + newDict = [] + if(len(list) > 0): + for i in list: + newDict.append(util.parse_job(self, i)) + return newDict \ No newline at end of file diff --git a/Python/api/job_handle.py b/Python/api/job_handle.py new file mode 100644 index 0000000..eddcc00 --- /dev/null +++ b/Python/api/job_handle.py @@ -0,0 +1,25 @@ +class JobHandle: + """A class for handling jobs sent to the framework + + Attributes: + client (BoaClient): the xmlrpc client + id (int): the jobs id + date (str): the date and time the job was submitted + dataset (dict): the dataset used to executed the job + exec_status (str): the execution status for the job + compiler_status (str): the compiler status for the job + """ + + def __init__(self, client, id, date, dataset, compiler_status, exec_status): + self.client = client + self.id = id + self.date = date + self.dataset = dataset + self.compiler_status = compiler_status + self.exec_status = exec_status + + def __str__(self): + """string output for a job""" + return str('id: ' + str(self.id) + ', date:' + str(self.date) + + ', dataset:' + str(self.dataset) + ', compiler_status: (' + str(self.compiler_status) + ')' + +', execution_status: (' + str(self.exec_status) + ')') \ No newline at end of file diff --git a/Python/api/util.py b/Python/api/util.py index 1c1503e..0e5b3c9 100644 --- a/Python/api/util.py +++ b/Python/api/util.py @@ -1,4 +1,5 @@ import xmlrpc +from job_handle import JobHandle class CookiesTransport(xmlrpc.client.Transport): """A Transport subclass that retains cookies over its lifetime.""" @@ -23,4 +24,7 @@ def parse_response(self, response): for header in response.msg.get_all("Set-Cookie"): cookie = header.split(";", 1)[0] self._cookies.append(cookie) - return super().parse_response(response) \ No newline at end of file + return super().parse_response(response) + +def parse_job(client, job): + return JobHandle(client, job['id'], job['submitted'], job['input'], job['compiler_status'], job['hadoop_status']) From e7e6ef259caba5f8d8d37dbfda6960b62a0421e5 Mon Sep 17 00:00:00 2001 From: Kamsiy Date: Tue, 23 Jul 2019 09:34:02 -0500 Subject: [PATCH 3/7] Add more methods for handling jobs --- Python/api/boa_client.py | 49 +++++++++++++++++++++++++++++++++++++++- Python/api/job_handle.py | 39 +++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/Python/api/boa_client.py b/Python/api/boa_client.py index 28a8610..a8f875b 100644 --- a/Python/api/boa_client.py +++ b/Python/api/boa_client.py @@ -154,4 +154,51 @@ def job_list(self, pub_only=False, offset=0, length=1000): if(len(list) > 0): for i in list: newDict.append(util.parse_job(self, i)) - return newDict \ No newline at end of file + return newDict + + def stop(self, job): + self.ensure_logged_in() + self.server.job.stop(job.id) + + def resubmit(self, job): + self.ensure_logged_in() + self.server.job.resubmit(job.id) + + def delete(self, job): + self.ensure_logged_in() + self.server.job.delete(job.id) + + def set_public(self, job, is_public): + self.ensure_logged_in() + if is_public is True: + self.server.job.setpublic(job.id, 1) + else: + self.server.job.setpublic(job.id, 0) + + def get_public(self, job): + self.ensure_logged_in() + result = self.server.job.public(job.id) + if result is 1: + return True + else: + return False + + def get_url(self, job): + self.ensure_logged_in() + return self.server.job.url(job.id) + + def get_public_url(self, job): + self.ensure_logged_in() + return self.server.job.publicurl(job.id) + + def get_compiler_errors(self, job): + self.ensure_logged_in() + return self.server.job.compilerErrors(job.id) + + def get_source(self, job): + self.ensure_logged_in() + return self.server.job.source(job) + + def get_output(self, job, start, length): + self.ensure_logged_in() + return self.server.job.output(job.id, start, length) \ No newline at end of file diff --git a/Python/api/job_handle.py b/Python/api/job_handle.py index eddcc00..a02089f 100644 --- a/Python/api/job_handle.py +++ b/Python/api/job_handle.py @@ -22,4 +22,41 @@ def __str__(self): """string output for a job""" return str('id: ' + str(self.id) + ', date:' + str(self.date) + ', dataset:' + str(self.dataset) + ', compiler_status: (' + str(self.compiler_status) + ')' - +', execution_status: (' + str(self.exec_status) + ')') \ No newline at end of file + +', execution_status: (' + str(self.exec_status) + ')') + + def stop(self): + return self.client.stop(self) + + def resubmit(self): + return self.client.resubmit(self) + + def delete(self): + return self.client.delete(self) + + def get_url(self): + return self.client.get_url(self) + + def set_public(self, status): + return self.client.set_public(self, status) + + def get_public(self): + return self.client.get_public(self) + + def get_public_url(self): + return self.client.get_public_url(self) + + def get_source(self): + return self.client.get_source(self) + + def get_compiler_errors(self): + return self.client.get_compiler_errors(self) + + def get_output(self, start=0, length=1000): + return self.client.get_output(self, start, length) + + def refresh(self): + job = self.client.get_job(self) + self.compiler_status = job['compiler_status'] + self.exec_status = job['execution_status'] + self.date = job['date'] + \ No newline at end of file From 9871e0798facd6e157bf4a93721f694a81ce3b80 Mon Sep 17 00:00:00 2001 From: Kamsiy Date: Tue, 23 Jul 2019 13:03:13 -0500 Subject: [PATCH 4/7] Update documentation --- Python/api/boa_client.py | 47 ++++++++++++++++++++++++++++++++++++++++ Python/api/job_handle.py | 15 +++++++++++++ 2 files changed, 62 insertions(+) diff --git a/Python/api/boa_client.py b/Python/api/boa_client.py index a8f875b..f5819b1 100644 --- a/Python/api/boa_client.py +++ b/Python/api/boa_client.py @@ -157,18 +157,39 @@ def job_list(self, pub_only=False, offset=0, length=1000): return newDict def stop(self, job): + """Stops the execution of a job + + Args: + job (JobHandle): the job whose execution you want to stop + """ self.ensure_logged_in() self.server.job.stop(job.id) def resubmit(self, job): + """Resubmits a job to the framework + + Args: + job (JobHandle): The job you want to resubmit + """ self.ensure_logged_in() self.server.job.resubmit(job.id) def delete(self, job): + """Deletes this job from the framework. + + Args: + job (JobHandle): + """ self.ensure_logged_in() self.server.job.delete(job.id) def set_public(self, job, is_public): + """Modifies the public/private status of this job. + + Args: + is_public (bool): 'True' to make it public, False to make it private + job (JobHandle) + """ self.ensure_logged_in() if is_public is True: self.server.job.setpublic(job.id, 1) @@ -176,6 +197,11 @@ def set_public(self, job, is_public): self.server.job.setpublic(job.id, 0) def get_public(self, job): + """Get the jobs public/private status. + + Args: + job (JobHandle) + """ self.ensure_logged_in() result = self.server.job.public(job.id) if result is 1: @@ -184,21 +210,42 @@ def get_public(self, job): return False def get_url(self, job): + """Retrieves the jobs URL. + + Args: + job (JobHandle) + """ self.ensure_logged_in() return self.server.job.url(job.id) def get_public_url(self, job): + """Get the jobs public page URL. + + Args: + job (JobHandle) + """ self.ensure_logged_in() return self.server.job.publicurl(job.id) def get_compiler_errors(self, job): + """Return any errors from trying to compile the job. + + Args: + job (JobHandle) + """ self.ensure_logged_in() return self.server.job.compilerErrors(job.id) def get_source(self, job): + """Return the source query for this job. + + Args: + job (JobHandle) + """ self.ensure_logged_in() return self.server.job.source(job) def get_output(self, job, start, length): + """Return the output for this job, if it finished successfully and has output.""" self.ensure_logged_in() return self.server.job.output(job.id, start, length) \ No newline at end of file diff --git a/Python/api/job_handle.py b/Python/api/job_handle.py index a02089f..23485d1 100644 --- a/Python/api/job_handle.py +++ b/Python/api/job_handle.py @@ -25,36 +25,51 @@ def __str__(self): +', execution_status: (' + str(self.exec_status) + ')') def stop(self): + """Stops the job if it is running.""" return self.client.stop(self) def resubmit(self): + """Resubmits this job.""" return self.client.resubmit(self) def delete(self): + """Deletes this job from the framework.""" return self.client.delete(self) def get_url(self): + """Retrieves the jobs URL.""" return self.client.get_url(self) def set_public(self, status): + """Modifies the public/private status of this job. + + Args: + status (bool): 'True' to make it public, False to make it private + """ return self.client.set_public(self, status) def get_public(self): + """Get the jobs public/private status.""" return self.client.get_public(self) def get_public_url(self): + """Get the jobs public page URL.""" return self.client.get_public_url(self) def get_source(self): + """Return the source query for this job.""" return self.client.get_source(self) def get_compiler_errors(self): + """Return any errors from trying to compile the job.""" return self.client.get_compiler_errors(self) def get_output(self, start=0, length=1000): + """Return the output for this job, if it finished successfully and has output.""" return self.client.get_output(self, start, length) def refresh(self): + """Refreshes the cached data for this job.""" job = self.client.get_job(self) self.compiler_status = job['compiler_status'] self.exec_status = job['execution_status'] From 3c32dd15459deacd9b601ad2bcdd20b920a7b23c Mon Sep 17 00:00:00 2001 From: Kamsiy Date: Tue, 23 Jul 2019 13:36:12 -0500 Subject: [PATCH 5/7] Rename certain methods --- Python/api/boa_client.py | 11 ++++++----- Python/api/job_handle.py | 16 ++++++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Python/api/boa_client.py b/Python/api/boa_client.py index f5819b1..e15a7cd 100644 --- a/Python/api/boa_client.py +++ b/Python/api/boa_client.py @@ -196,7 +196,7 @@ def set_public(self, job, is_public): else: self.server.job.setpublic(job.id, 0) - def get_public(self, job): + def public_status(self, job): """Get the jobs public/private status. Args: @@ -218,7 +218,7 @@ def get_url(self, job): self.ensure_logged_in() return self.server.job.url(job.id) - def get_public_url(self, job): + def public_url(self, job): """Get the jobs public page URL. Args: @@ -236,7 +236,7 @@ def get_compiler_errors(self, job): self.ensure_logged_in() return self.server.job.compilerErrors(job.id) - def get_source(self, job): + def source(self, job): """Return the source query for this job. Args: @@ -245,7 +245,8 @@ def get_source(self, job): self.ensure_logged_in() return self.server.job.source(job) - def get_output(self, job, start, length): + def output(self, job, start, length): """Return the output for this job, if it finished successfully and has output.""" self.ensure_logged_in() - return self.server.job.output(job.id, start, length) \ No newline at end of file + return self.server.job.output(job.id, start, length) + \ No newline at end of file diff --git a/Python/api/job_handle.py b/Python/api/job_handle.py index 23485d1..fcf4c3b 100644 --- a/Python/api/job_handle.py +++ b/Python/api/job_handle.py @@ -48,25 +48,25 @@ def set_public(self, status): """ return self.client.set_public(self, status) - def get_public(self): + def public_status(self): """Get the jobs public/private status.""" - return self.client.get_public(self) + return self.client.public_status(self) - def get_public_url(self): + def public_url(self): """Get the jobs public page URL.""" - return self.client.get_public_url(self) + return self.client.public_url(self) - def get_source(self): + def source(self): """Return the source query for this job.""" - return self.client.get_source(self) + return self.client.source(self) def get_compiler_errors(self): """Return any errors from trying to compile the job.""" return self.client.get_compiler_errors(self) - def get_output(self, start=0, length=1000): + def output(self, start=0, length=1000): """Return the output for this job, if it finished successfully and has output.""" - return self.client.get_output(self, start, length) + return self.client.output(self, start, length) def refresh(self): """Refreshes the cached data for this job.""" From 76a41918ba41fff7aaedf82a4b5437a759335df2 Mon Sep 17 00:00:00 2001 From: Kamsiy Date: Mon, 2 Sep 2019 10:44:54 -0500 Subject: [PATCH 6/7] Fix job output --- Python/api/boa_client.py | 17 +++++++++-------- Python/api/job_handle.py | 13 ++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Python/api/boa_client.py b/Python/api/boa_client.py index e15a7cd..050d5f2 100644 --- a/Python/api/boa_client.py +++ b/Python/api/boa_client.py @@ -120,8 +120,8 @@ def query(self, query, dataset=None): """ self.ensure_logged_in() id = 0 if dataset is None else dataset.get_id() - job = self.server.boa.submit(query, self.get_datasets()[id]['id']) - return parse_job(self, job) + job = self.server.boa.submit(query, self.datasets()[id]['id']) + return util.parse_job(self, job) def get_job(self, id): """Retrieves a job given an id. @@ -133,7 +133,7 @@ def get_job(self, id): JobHandle: the desired job. """ self.ensure_logged_in() - return parse_job(self.server, self.server.boa.job(id)) + return util.parse_job(self, self.server.boa.job(id)) def job_list(self, pub_only=False, offset=0, length=1000): """Returns a list of the most recent jobs, based on an offset and length. @@ -243,10 +243,11 @@ def source(self, job): job (JobHandle) """ self.ensure_logged_in() - return self.server.job.source(job) + return self.server.job.source(job.id) - def output(self, job, start, length): - """Return the output for this job, if it finished successfully and has output.""" + def output(self, job): + """Return the output for this job, if it finished successfully and has an output.""" self.ensure_logged_in() - return self.server.job.output(job.id, start, length) - \ No newline at end of file + if job.exec_status != "Finished": + return "Job is currently running" + return self.server.job.output(job.id) \ No newline at end of file diff --git a/Python/api/job_handle.py b/Python/api/job_handle.py index fcf4c3b..f5c9d47 100644 --- a/Python/api/job_handle.py +++ b/Python/api/job_handle.py @@ -64,14 +64,13 @@ def get_compiler_errors(self): """Return any errors from trying to compile the job.""" return self.client.get_compiler_errors(self) - def output(self, start=0, length=1000): + def output(self): """Return the output for this job, if it finished successfully and has output.""" - return self.client.output(self, start, length) + return self.client.output(self) def refresh(self): """Refreshes the cached data for this job.""" - job = self.client.get_job(self) - self.compiler_status = job['compiler_status'] - self.exec_status = job['execution_status'] - self.date = job['date'] - \ No newline at end of file + job = self.client.get_job(self.id) + self.compiler_status = job.compiler_status + self.exec_status = job.exec_status + self.date = job.date \ No newline at end of file From 3015e246029a751d0e7804101f51065f3d539910 Mon Sep 17 00:00:00 2001 From: Kamsiy Date: Mon, 2 Sep 2019 12:14:16 -0500 Subject: [PATCH 7/7] Add exceptions --- Python/api/boa_client.py | 231 ++++++++++++++++++++++++++++++--------- Python/api/exceptions.py | 6 - 2 files changed, 178 insertions(+), 59 deletions(-) delete mode 100644 Python/api/exceptions.py diff --git a/Python/api/boa_client.py b/Python/api/boa_client.py index 050d5f2..369013e 100644 --- a/Python/api/boa_client.py +++ b/Python/api/boa_client.py @@ -1,9 +1,15 @@ import xmlrpc.client -import exceptions +import traceback import util BOA_PROXY = "http://boa.cs.iastate.edu/boa/?q=boa/api" +class NotLoggedInException(Exception): + pass + +class BoaException(Exception): + pass + class BoaClient(object): """ A client class for accessing boa's api @@ -25,16 +31,26 @@ def login(self, username, password): username (str): username for boa account password (str): password for boa account """ - self.__logged_in = True - response = self.server.user.login(username, password) - self.trans.add_csrf(response["token"]) - return response - + try: + self.__logged_in = True + response = self.server.user.login(username, password) + self.trans.add_csrf(response["token"]) + return response + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) + def close(self): - """Log out of the boa framework using the remote api""" + """Log out of the boa framework using the remote api + + Raises: + BoaException: if theres an issue reading from the server + """ self.ensure_logged_in() - self.server.user.logout() - self.__logged_in = False + try: + self.server.user.logout() + self.__logged_in = False + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def ensure_logged_in(self): """Checks if a user is currently logged in through the remote api @@ -53,22 +69,34 @@ def datasets(self): Returns: list: a list of boa datasets + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - return self.server.boa.datasets() + try: + return self.server.boa.datasets() + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def dataset_names(self): """Retrieves a list of names of all datasets provided by boa Returns: list: the dataset names + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - dataset_names = [] - datasets = self.datasets() - for x in datasets: - dataset_names.append(x['name']) - return dataset_names + try: + dataset_names = [] + datasets = self.datasets() + for x in datasets: + dataset_names.append(x['name']) + return dataset_names + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def get_dataset(self, name): """Retrieves a dataset given a name. @@ -78,22 +106,34 @@ def get_dataset(self, name): Returns: dict: a dictionary with the keys id and name + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - for x in self.datasets(): - if x['name'] == name: - return x - return None + try: + for x in self.datasets(): + if x['name'] == name: + return x + return None + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def last_job(self): """Retrieves the most recently submitted job Returns: JobHandle: the last submitted job + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - jobs = self.job_list(False, 0, 1) - return jobs[0] + try: + jobs = self.job_list(False, 0, 1) + return jobs[0] + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def job_count(self, pub_only=False): """Retrieves the number of jobs submitted by a user @@ -104,9 +144,15 @@ def job_count(self, pub_only=False): Returns: int: the number of jobs submitted by a user + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - return self.server.boa.count(pub_only) + try: + return self.server.boa.count(pub_only) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def query(self, query, dataset=None): """Submits a new query to Boa to query the specified and returns a handle to the new job. @@ -117,11 +163,17 @@ def query(self, query, dataset=None): Returns: (JobHandle) a job + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - id = 0 if dataset is None else dataset.get_id() - job = self.server.boa.submit(query, self.datasets()[id]['id']) - return util.parse_job(self, job) + try: + id = 0 if dataset is None else dataset.get_id() + job = self.server.boa.submit(query, self.datasets()[id]['id']) + return util.parse_job(self, job) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def get_job(self, id): """Retrieves a job given an id. @@ -131,9 +183,15 @@ def get_job(self, id): Returns: JobHandle: the desired job. + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - return util.parse_job(self, self.server.boa.job(id)) + try: + return util.parse_job(self, self.server.boa.job(id)) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def job_list(self, pub_only=False, offset=0, length=1000): """Returns a list of the most recent jobs, based on an offset and length. @@ -147,41 +205,65 @@ def job_list(self, pub_only=False, offset=0, length=1000): Returns: list: a list of jobs where each element is a jobHandle + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - list = self.server.boa.jobs(pub_only, offset, length) - newDict = [] - if(len(list) > 0): - for i in list: - newDict.append(util.parse_job(self, i)) - return newDict + try: + list = self.server.boa.jobs(pub_only, offset, length) + newDict = [] + if(len(list) > 0): + for i in list: + newDict.append(util.parse_job(self, i)) + return newDict + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def stop(self, job): """Stops the execution of a job Args: job (JobHandle): the job whose execution you want to stop + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - self.server.job.stop(job.id) + try: + self.server.job.stop(job.id) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def resubmit(self, job): """Resubmits a job to the framework Args: job (JobHandle): The job you want to resubmit + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - self.server.job.resubmit(job.id) + try: + self.server.job.resubmit(job.id) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def delete(self, job): """Deletes this job from the framework. Args: - job (JobHandle): + job (JobHandle): the job you want to delete + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - self.server.job.delete(job.id) + try: + self.server.job.delete(job.id) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def set_public(self, job, is_public): """Modifies the public/private status of this job. @@ -189,65 +271,108 @@ def set_public(self, job, is_public): Args: is_public (bool): 'True' to make it public, False to make it private job (JobHandle) + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - if is_public is True: - self.server.job.setpublic(job.id, 1) - else: - self.server.job.setpublic(job.id, 0) + try: + if is_public is True: + self.server.job.setpublic(job.id, 1) + else: + self.server.job.setpublic(job.id, 0) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def public_status(self, job): """Get the jobs public/private status. Args: job (JobHandle) + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - result = self.server.job.public(job.id) - if result is 1: - return True - else: - return False + try: + result = self.server.job.public(job.id) + if result is 1: + return True + else: + return False + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def get_url(self, job): """Retrieves the jobs URL. Args: job (JobHandle) + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - return self.server.job.url(job.id) + try: + return self.server.job.url(job.id) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def public_url(self, job): """Get the jobs public page URL. Args: job (JobHandle) + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - return self.server.job.publicurl(job.id) + try: + return self.server.job.publicurl(job.id) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def get_compiler_errors(self, job): """Return any errors from trying to compile the job. Args: job (JobHandle) + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - return self.server.job.compilerErrors(job.id) + try: + return self.server.job.compilerErrors(job.id) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def source(self, job): """Return the source query for this job. Args: job (JobHandle) + + Raises: + BoaException: if theres an issue reading from the server """ self.ensure_logged_in() - return self.server.job.source(job.id) + try: + return self.server.job.source(job.id) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) def output(self, job): - """Return the output for this job, if it finished successfully and has an output.""" + """Return the output for this job, if it finished successfully and has an output. + + Raises: + BoaException: if theres an issue reading from the server + """ self.ensure_logged_in() - if job.exec_status != "Finished": - return "Job is currently running" - return self.server.job.output(job.id) \ No newline at end of file + try: + if job.exec_status != "Finished": + return "Job is currently running" + return self.server.job.output(job.id) + except xmlrpc.client.Fault as e: + raise BoaException(e).with_traceback(e.__traceback__) \ No newline at end of file diff --git a/Python/api/exceptions.py b/Python/api/exceptions.py deleted file mode 100644 index 4e1cb7a..0000000 --- a/Python/api/exceptions.py +++ /dev/null @@ -1,6 +0,0 @@ -class NotLoggedInException(Exception): - pass - - -class BoaException(Exception): - pass \ No newline at end of file