From 0adccc747f01aa08bdfff4aa62549f370910bf11 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Tue, 29 May 2018 15:24:05 -0700 Subject: [PATCH 1/5] initial checkin for get background jobs --- test/test_job.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_job.py b/test/test_job.py index 674e54c67..21e36e94b 100644 --- a/test/test_job.py +++ b/test/test_job.py @@ -1,9 +1,9 @@ import unittest import os from datetime import datetime +from tableauserverclient.datetime_helpers import utc import requests_mock import tableauserverclient as TSC -from tableauserverclient.datetime_helpers import utc TEST_ASSET_DIR = os.path.join(os.path.dirname(__file__), 'assets') @@ -31,6 +31,7 @@ def test_get(self): created_at = datetime(2018, 5, 22, 13, 0, 29, tzinfo=utc) started_at = datetime(2018, 5, 22, 13, 0, 37, tzinfo=utc) ended_at = datetime(2018, 5, 22, 13, 0, 45, tzinfo=utc) + self.assertEquals(1, pagination_item.total_available) self.assertEquals('2eef4225-aa0c-41c4-8662-a76d89ed7336', job.id) self.assertEquals('Success', job.status) From fefa23d395d74a6f5c9eee38c064df1cfe7ca7f9 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Wed, 30 May 2018 07:37:56 -0700 Subject: [PATCH 2/5] addressed code review feedback --- test/test_job.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_job.py b/test/test_job.py index 21e36e94b..276111650 100644 --- a/test/test_job.py +++ b/test/test_job.py @@ -1,9 +1,9 @@ import unittest import os from datetime import datetime -from tableauserverclient.datetime_helpers import utc import requests_mock import tableauserverclient as TSC +from tableauserverclient.datetime_helpers import utc TEST_ASSET_DIR = os.path.join(os.path.dirname(__file__), 'assets') From 0f23526b6a5004351a29ea9872d1680e86641bd9 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Thu, 31 May 2018 08:31:07 -0700 Subject: [PATCH 3/5] added cancel job --- samples/kill_all_jobs.py | 47 +++++++++++++++++++ .../server/endpoint/endpoint.py | 2 +- .../server/endpoint/jobs_endpoint.py | 9 ++++ tableauserverclient/server/request_options.py | 7 +++ test/test_job.py | 5 ++ 5 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 samples/kill_all_jobs.py diff --git a/samples/kill_all_jobs.py b/samples/kill_all_jobs.py new file mode 100644 index 000000000..aca66b879 --- /dev/null +++ b/samples/kill_all_jobs.py @@ -0,0 +1,47 @@ +#### +# This script demonstrates how to list all of the workbooks or datasources +# +# To run the script, you must have installed Python 2.7.X or 3.3 and later. +#### + +import argparse +import getpass +import logging + +import tableauserverclient as TSC + + +def main(): + parser = argparse.ArgumentParser(description='List out the names and LUIDs for different resource types') + parser.add_argument('--server', '-s', required=True, help='server address') + parser.add_argument('--site', '-S', default=None, help='site to log into, do not specify for default site') + parser.add_argument('--username', '-u', required=True, help='username to sign into server') + parser.add_argument('--password', '-p', default=None, help='password for the user') + + parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error', + help='desired logging level (set to error by default)') + + args = parser.parse_args() + + if args.password is None: + password = getpass.getpass("Password: ") + else: + password = args.password + + # Set logging level based on user input, or error by default + logging_level = getattr(logging, args.logging_level.upper()) + logging.basicConfig(level=logging_level) + + # SIGN IN + tableau_auth = TSC.TableauAuth(args.username, password, args.site) + server = TSC.Server(args.server, use_server_version=True) + with server.auth.sign_in(tableau_auth): + req = TSC.RequestOptions() + + req.filter.add(TSC.Filter("progress", TSC.RequestOptions.Operator.LessThanOrEqual, 0)) + for job in TSC.Pager(server.jobs.get, request_opts=req): + print(server.jobs.cancel(job.id), job.id, job.status, job.type) + + +if __name__ == '__main__': + main() diff --git a/tableauserverclient/server/endpoint/endpoint.py b/tableauserverclient/server/endpoint/endpoint.py index 1efb32f89..994d2133d 100644 --- a/tableauserverclient/server/endpoint/endpoint.py +++ b/tableauserverclient/server/endpoint/endpoint.py @@ -76,7 +76,7 @@ def delete_request(self, url): # We don't return anything for a delete self._make_request(self.parent_srv.session.delete, url, auth_token=self.parent_srv.auth_token) - def put_request(self, url, xml_request, content_type='text/xml'): + def put_request(self, url, xml_request=None, content_type='text/xml'): return self._make_request(self.parent_srv.session.put, url, content=xml_request, auth_token=self.parent_srv.auth_token, diff --git a/tableauserverclient/server/endpoint/jobs_endpoint.py b/tableauserverclient/server/endpoint/jobs_endpoint.py index 007f550ae..ab7c7f0fc 100644 --- a/tableauserverclient/server/endpoint/jobs_endpoint.py +++ b/tableauserverclient/server/endpoint/jobs_endpoint.py @@ -1,5 +1,6 @@ from .endpoint import Endpoint, api from .. import JobItem, BackgroundJobItem, PaginationItem +from ..request_options import RequestOptionsBase import logging logger = logging.getLogger('tableau.endpoint.jobs') @@ -17,12 +18,20 @@ def get(self, job_id=None, req_options=None): import warnings warnings.warn("Jobs.get(job_id) is deprecated, update code to use Jobs.get_by_id(job_id)") return self.get_by_id(job_id) + if isinstance(job_id, RequestOptionsBase): + req_options = job_id + self.parent_srv.assert_at_least_version('3.1') server_response = self.get_request(self.baseurl, req_options) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) jobs = BackgroundJobItem.from_response(server_response.content, self.parent_srv.namespace) return jobs, pagination_item + @api(version='3.1') + def cancel(self, job_id): + url = '{0}/{1}'.format(self.baseurl, job_id) + return self.put_request(url) + @api(version='2.6') def get_by_id(self, job_id): logger.info('Query for information about job ' + job_id) diff --git a/tableauserverclient/server/request_options.py b/tableauserverclient/server/request_options.py index be00e8975..0e3601a25 100644 --- a/tableauserverclient/server/request_options.py +++ b/tableauserverclient/server/request_options.py @@ -13,20 +13,27 @@ class Operator: In = 'in' class Field: + Args = 'args' + CompletedAt = 'completedAt' CreatedAt = 'createdAt' DomainName = 'domainName' DomainNickname = 'domainNickname' HitsTotal = 'hitsTotal' IsLocal = 'isLocal' + JobType = 'jobType' LastLogin = 'lastLogin' MinimumSiteRole = 'minimumSiteRole' Name = 'name' + Notes = 'notes' OwnerDomain = 'ownerDomain' OwnerEmail = 'ownerEmail' OwnerName = 'ownerName' + Progress = 'progress' ProjectName = 'projectName' SiteRole = 'siteRole' + Subtitle = 'subtitle' Tags = 'tags' + Title = 'title' Type = 'type' UpdatedAt = 'updatedAt' UserCount = 'userCount' diff --git a/test/test_job.py b/test/test_job.py index 276111650..5da0f76fa 100644 --- a/test/test_job.py +++ b/test/test_job.py @@ -44,3 +44,8 @@ def test_get(self): def test_get_before_signin(self): self.server._auth_token = None self.assertRaises(TSC.NotSignedInError, self.server.jobs.get) + + def test_cancel(self): + with requests_mock.mock() as m: + m.put(self.baseurl + '/ee8c6e70-43b6-11e6-af4f-f7b0d8e20760', status_code=204) + self.server.jobs.cancel('ee8c6e70-43b6-11e6-af4f-f7b0d8e20760') From 022b3030565b318c62feb3f9d3b4e1fc92e6a73b Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Thu, 31 May 2018 08:41:21 -0700 Subject: [PATCH 4/5] fixing whitespace issues --- tableauserverclient/server/endpoint/jobs_endpoint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tableauserverclient/server/endpoint/jobs_endpoint.py b/tableauserverclient/server/endpoint/jobs_endpoint.py index ab7c7f0fc..f3432d605 100644 --- a/tableauserverclient/server/endpoint/jobs_endpoint.py +++ b/tableauserverclient/server/endpoint/jobs_endpoint.py @@ -20,7 +20,7 @@ def get(self, job_id=None, req_options=None): return self.get_by_id(job_id) if isinstance(job_id, RequestOptionsBase): req_options = job_id - + self.parent_srv.assert_at_least_version('3.1') server_response = self.get_request(self.baseurl, req_options) pagination_item = PaginationItem.from_response(server_response.content, self.parent_srv.namespace) From 09ef2ff68aad021a18189553f8cee21ae6e16aac Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Fri, 1 Jun 2018 09:04:41 -0700 Subject: [PATCH 5/5] addressing small nits in the sample and the docs --- samples/kill_all_jobs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/kill_all_jobs.py b/samples/kill_all_jobs.py index aca66b879..9c5f52a50 100644 --- a/samples/kill_all_jobs.py +++ b/samples/kill_all_jobs.py @@ -1,5 +1,5 @@ #### -# This script demonstrates how to list all of the workbooks or datasources +# This script demonstrates how to kill all of the running jobs # # To run the script, you must have installed Python 2.7.X or 3.3 and later. #### @@ -12,7 +12,7 @@ def main(): - parser = argparse.ArgumentParser(description='List out the names and LUIDs for different resource types') + parser = argparse.ArgumentParser(description='Cancel all of the running background jobs') parser.add_argument('--server', '-s', required=True, help='server address') parser.add_argument('--site', '-S', default=None, help='site to log into, do not specify for default site') parser.add_argument('--username', '-u', required=True, help='username to sign into server') @@ -39,7 +39,7 @@ def main(): req = TSC.RequestOptions() req.filter.add(TSC.Filter("progress", TSC.RequestOptions.Operator.LessThanOrEqual, 0)) - for job in TSC.Pager(server.jobs.get, request_opts=req): + for job in TSC.Pager(server.jobs, request_opts=req): print(server.jobs.cancel(job.id), job.id, job.status, job.type)