From c3d3b83296f25cc1e1a94dde8307dae35ad7ec43 Mon Sep 17 00:00:00 2001 From: Tyler Doyle Date: Tue, 24 Jan 2017 16:10:50 +0100 Subject: [PATCH 01/12] Add api annotation to all current endpoints (#125) Part two of #125 This backfills all existing APIs with their minimum version. Checking this in early in release cycle for baketime. --- tableauserverclient/server/endpoint/workbooks_endpoint.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tableauserverclient/server/endpoint/workbooks_endpoint.py b/tableauserverclient/server/endpoint/workbooks_endpoint.py index 1f9bbe957..b853c65aa 100644 --- a/tableauserverclient/server/endpoint/workbooks_endpoint.py +++ b/tableauserverclient/server/endpoint/workbooks_endpoint.py @@ -1,4 +1,8 @@ +<<<<<<< 9b2b265b38a0e94edc49aef27a5f6f14900d2a77 from .endpoint import Endpoint, api, parameter_added_in +======= +from .endpoint import Endpoint, api +>>>>>>> Add api annotation to all current endpoints (#125) from .exceptions import MissingRequiredFieldError from .fileuploads_endpoint import Fileuploads from .resource_tagger import _ResourceTagger From 6c6a42859690fa85e145f74b1f2b4b0cc89a8dea Mon Sep 17 00:00:00 2001 From: Tyler Doyle Date: Mon, 13 Feb 2017 14:08:02 -0800 Subject: [PATCH 02/12] Download with extract_only and parameter checking (#143) * Add a new decorator that checks parameters against the version. Used with the @api decorator. * Add extract_only flags to workbooks and data sources, protected behind v2.5 flag --- tableauserverclient/server/endpoint/workbooks_endpoint.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tableauserverclient/server/endpoint/workbooks_endpoint.py b/tableauserverclient/server/endpoint/workbooks_endpoint.py index b853c65aa..1f9bbe957 100644 --- a/tableauserverclient/server/endpoint/workbooks_endpoint.py +++ b/tableauserverclient/server/endpoint/workbooks_endpoint.py @@ -1,8 +1,4 @@ -<<<<<<< 9b2b265b38a0e94edc49aef27a5f6f14900d2a77 from .endpoint import Endpoint, api, parameter_added_in -======= -from .endpoint import Endpoint, api ->>>>>>> Add api annotation to all current endpoints (#125) from .exceptions import MissingRequiredFieldError from .fileuploads_endpoint import Fileuploads from .resource_tagger import _ResourceTagger From bc378054f90ae749d8cca2cb8c0eede2d6a5691b Mon Sep 17 00:00:00 2001 From: Jackson Huang Date: Wed, 14 Dec 2016 15:19:08 -0800 Subject: [PATCH 03/12] Response to code reviews. Put all request options into 1 file. renamed sample to download_view_image.py. Comments clean up --- tableauserverclient/server/request_options.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tableauserverclient/server/request_options.py b/tableauserverclient/server/request_options.py index dade12205..876363544 100644 --- a/tableauserverclient/server/request_options.py +++ b/tableauserverclient/server/request_options.py @@ -75,3 +75,22 @@ def apply_query_params(self, url): params.append('resolution={0}'.format(self.imageresolution)) return "{0}?{1}".format(url, '&'.join(params)) + +class ImageRequestOptions(RequestOptionsBase): + # if 'high' isn't specified, the REST API endpoint returns an image with standard resolution + class Resolution: + High = 'high' + + def __init__(self, imageresolution=None): + self.imageresolution = imageresolution + + def image_resolution(self, imageresolution): + self.imageresolution = imageresolution + return self + + def apply_query_params(self, url): + params = [] + if self.image_resolution: + params.append('resolution={0}'.format(self.imageresolution)) + + return "{0}?{1}".format(url, '&'.join(params)) From 06f535e9599995d132ca2f7d8442595fda9d5dc5 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Tue, 7 Feb 2017 13:25:38 -0800 Subject: [PATCH 04/12] initial implement of get all and get specific for Extract Refresh Tasks --- samples/refresh_tasks.py | 46 +++++++++++++++++++ tableauserverclient/__init__.py | 2 +- tableauserverclient/models/__init__.py | 1 + tableauserverclient/models/schedule_item.py | 23 ++++++---- tableauserverclient/models/task_item.py | 38 +++++++++++++++ tableauserverclient/server/__init__.py | 2 +- .../server/endpoint/__init__.py | 1 + .../server/endpoint/tasks_endpoint.py | 30 ++++++++++++ tableauserverclient/server/server.py | 3 +- 9 files changed, 135 insertions(+), 11 deletions(-) create mode 100644 samples/refresh_tasks.py create mode 100644 tableauserverclient/models/task_item.py create mode 100644 tableauserverclient/server/endpoint/tasks_endpoint.py diff --git a/samples/refresh_tasks.py b/samples/refresh_tasks.py new file mode 100644 index 000000000..9c6bf6196 --- /dev/null +++ b/samples/refresh_tasks.py @@ -0,0 +1,46 @@ +#### +# TODO +#### + +import argparse +import getpass +import logging + +import tableauserverclient as TSC + + +def main(): + + parser = argparse.ArgumentParser(description='Get all of the refresh tasks available on a server') + parser.add_argument('--server', '-s', required=True, help='server address') + parser.add_argument('--username', '-u', required=True, help='username to sign into server') + parser.add_argument('--site', '-S', default=None) + parser.add_argument('--id', '-i', default=None) + 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() + + password = getpass.getpass("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) + server.version = '2.5' + with server.auth.sign_in(tableau_auth): + import pprint + + if args.id: + task = server.tasks.get_by_id(args.id) + pprint.pprint(task) + else: + tasks, pagination = server.tasks.get() + pprint.pprint(tasks) + + +if __name__ == '__main__': + main() diff --git a/tableauserverclient/__init__.py b/tableauserverclient/__init__.py index acf639c56..6cc3cdb48 100644 --- a/tableauserverclient/__init__.py +++ b/tableauserverclient/__init__.py @@ -2,7 +2,7 @@ from .models import ConnectionCredentials, ConnectionItem, DatasourceItem,\ GroupItem, PaginationItem, ProjectItem, ScheduleItem, \ SiteItem, TableauAuth, UserItem, ViewItem, WorkbookItem, UnpopulatedPropertyError, \ - HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval, IntervalItem + HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval, IntervalItem , TaskItem from .server import RequestOptions, ImageRequestOptions, Filter, Sort, Server, ServerResponseError,\ MissingRequiredFieldError, NotSignedInError, Pager diff --git a/tableauserverclient/models/__init__.py b/tableauserverclient/models/__init__.py index b248ea399..cb26f4eaa 100644 --- a/tableauserverclient/models/__init__.py +++ b/tableauserverclient/models/__init__.py @@ -10,6 +10,7 @@ from .server_info_item import ServerInfoItem from .site_item import SiteItem from .tableau_auth import TableauAuth +from .task_item import TaskItem from .user_item import UserItem from .view_item import ViewItem from .workbook_item import WorkbookItem diff --git a/tableauserverclient/models/schedule_item.py b/tableauserverclient/models/schedule_item.py index 84b070044..476850350 100644 --- a/tableauserverclient/models/schedule_item.py +++ b/tableauserverclient/models/schedule_item.py @@ -33,6 +33,10 @@ def __init__(self, name, priority, schedule_type, execution_order, interval_item self.priority = priority self.schedule_type = schedule_type + def __repr__(self): + print(self.__dict__) + return "".format(**self.__dict__) + @property def created_at(self): return self._created_at @@ -106,7 +110,7 @@ def _parse_common_tags(self, schedule_xml): (_, name, _, _, updated_at, _, next_run_at, end_schedule_at, execution_order, priority, interval_item) = self._parse_element(schedule_xml) - self._set_values(id=None, + self._set_values(id_=None, name=name, state=None, created_at=None, @@ -120,10 +124,10 @@ def _parse_common_tags(self, schedule_xml): return self - def _set_values(self, id, name, state, created_at, updated_at, schedule_type, + def _set_values(self, id_, name, state, created_at, updated_at, schedule_type, next_run_at, end_schedule_at, execution_order, priority, interval_item): - if id is not None: - self._id = id + if id_ is not None: + self._id = id_ if name: self._name = name if state: @@ -145,18 +149,21 @@ def _set_values(self, id, name, state, created_at, updated_at, schedule_type, if interval_item: self._interval_item = interval_item - @classmethod def from_response(cls, resp): - all_schedule_items = [] parsed_response = ET.fromstring(resp) + return cls.from_element(parsed_response) + + @classmethod + def from_element(cls, parsed_response): + all_schedule_items = [] all_schedule_xml = parsed_response.findall('.//t:schedule', namespaces=NAMESPACE) for schedule_xml in all_schedule_xml: - (id, name, state, created_at, updated_at, schedule_type, next_run_at, + (id_, name, state, created_at, updated_at, schedule_type, next_run_at, end_schedule_at, execution_order, priority, interval_item) = cls._parse_element(schedule_xml) schedule_item = cls(name, priority, schedule_type, execution_order, interval_item) - schedule_item._set_values(id=id, + schedule_item._set_values(id_=id_, name=None, state=state, created_at=created_at, diff --git a/tableauserverclient/models/task_item.py b/tableauserverclient/models/task_item.py new file mode 100644 index 000000000..f41ca04ba --- /dev/null +++ b/tableauserverclient/models/task_item.py @@ -0,0 +1,38 @@ +import xml.etree.ElementTree as ET +from .. import NAMESPACE +from .schedule_item import ScheduleItem + + +class TaskItem(object): + def __init__(self, id_, task_type, priority, consecutive_failed_count=0, schedule_id=None): + self.id = id_ + self.task_type = task_type + self.priority = priority + self.consecutive_failed_count = consecutive_failed_count + self.schedule_id = schedule_id + + def __repr__(self): + return "".format( + **self.__dict__) + + @classmethod + def from_response(cls, xml): + parsed_response = ET.fromstring(xml) + all_tasks_xml = parsed_response.findall('.//t:task', namespaces=NAMESPACE) + + all_tasks = (TaskItem._parse_task(x) for x in all_tasks_xml) + + return list(all_tasks) + + @classmethod + def _parse_task(cls, element): + schedule = None + schedule_element = element.find('.//t:schedule', namespaces=NAMESPACE) + if schedule_element is not None: + schedule = schedule_element.get('id', None) + task_type = element.get('type', None) + priority = int(element.get('priority', -1)) + consecutive_failed_count = int(element.get('consecutiveFailedCount', 0)) + id_ = element.get('id', None) + return cls(id_, task_type, priority, consecutive_failed_count, schedule) \ No newline at end of file diff --git a/tableauserverclient/server/__init__.py b/tableauserverclient/server/__init__.py index 504d5b5b8..ab386c0ca 100644 --- a/tableauserverclient/server/__init__.py +++ b/tableauserverclient/server/__init__.py @@ -4,7 +4,7 @@ from .sort import Sort from .. import ConnectionItem, DatasourceItem,\ GroupItem, PaginationItem, ProjectItem, ScheduleItem, SiteItem, TableauAuth,\ - UserItem, ViewItem, WorkbookItem, NAMESPACE + UserItem, ViewItem, WorkbookItem, TaskItem, NAMESPACE from .endpoint import Auth, Datasources, Endpoint, Groups, Projects, Schedules, \ Sites, Users, Views, Workbooks, ServerResponseError, MissingRequiredFieldError from .server import Server diff --git a/tableauserverclient/server/endpoint/__init__.py b/tableauserverclient/server/endpoint/__init__.py index d9dca0f42..323934f12 100644 --- a/tableauserverclient/server/endpoint/__init__.py +++ b/tableauserverclient/server/endpoint/__init__.py @@ -7,6 +7,7 @@ from .schedules_endpoint import Schedules from .server_info_endpoint import ServerInfo from .sites_endpoint import Sites +from .tasks_endpoint import Tasks from .users_endpoint import Users from .views_endpoint import Views from .workbooks_endpoint import Workbooks diff --git a/tableauserverclient/server/endpoint/tasks_endpoint.py b/tableauserverclient/server/endpoint/tasks_endpoint.py new file mode 100644 index 000000000..92f7eb7e3 --- /dev/null +++ b/tableauserverclient/server/endpoint/tasks_endpoint.py @@ -0,0 +1,30 @@ +from .endpoint import Endpoint +from .. import TaskItem, PaginationItem +import logging + +logger = logging.getLogger('tableau.endpoint.tasks') + + +class Tasks(Endpoint): + @property + def baseurl(self): + return "{0}/sites/{1}/tasks/extract-refreshes".format(self.parent_srv.baseurl, + self.parent_srv.site_id) + + def get(self, req_options=None): + logger.info('Querying all tasks for the site') + url = self.baseurl + server_response = self.get_request(url, req_options) + + pagination_item = PaginationItem.from_response(server_response.content) + all_extract_tasks = TaskItem.from_response(server_response.content) + return all_extract_tasks, pagination_item + + def get_by_id(self, task_id): + if not task_id: + error = "No Task ID provided" + raise ValueError(error) + logger.info("Querying a single task by id ({})".format(task_id)) + url = "{}/{}".format(self.baseurl, task_id) + server_response = self.get_request(url) + return TaskItem.from_response(server_response.content)[0] diff --git a/tableauserverclient/server/server.py b/tableauserverclient/server/server.py index a998bd76b..339262fba 100644 --- a/tableauserverclient/server/server.py +++ b/tableauserverclient/server/server.py @@ -2,7 +2,7 @@ from .exceptions import NotSignedInError from .endpoint import Sites, Views, Users, Groups, Workbooks, Datasources, Projects, Auth, \ - Schedules, ServerInfo, ServerInfoEndpointNotFoundError + Schedules, ServerInfo, Tasks, ServerInfoEndpointNotFoundError import requests @@ -40,6 +40,7 @@ def __init__(self, server_address): self.projects = Projects(self) self.schedules = Schedules(self) self.server_info = ServerInfo(self) + self.tasks = Tasks(self) def add_http_options(self, options_dict): self._http_options.update(options_dict) From 104799b45da6fdf8994bbe4abd4f41af88e50589 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Tue, 7 Feb 2017 14:25:18 -0800 Subject: [PATCH 05/12] fixing test failure in the schedule_item code --- tableauserverclient/models/schedule_item.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tableauserverclient/models/schedule_item.py b/tableauserverclient/models/schedule_item.py index 476850350..f22fd0d48 100644 --- a/tableauserverclient/models/schedule_item.py +++ b/tableauserverclient/models/schedule_item.py @@ -149,6 +149,7 @@ def _set_values(self, id_, name, state, created_at, updated_at, schedule_type, if interval_item: self._interval_item = interval_item + @classmethod def from_response(cls, resp): parsed_response = ET.fromstring(resp) return cls.from_element(parsed_response) From e8a49f5ed0d168c455cf0095f9201f185cc84e3d Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Tue, 7 Feb 2017 14:35:20 -0800 Subject: [PATCH 06/12] pep8 fixes --- tableauserverclient/__init__.py | 2 +- tableauserverclient/models/task_item.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tableauserverclient/__init__.py b/tableauserverclient/__init__.py index 6cc3cdb48..47d14dbfb 100644 --- a/tableauserverclient/__init__.py +++ b/tableauserverclient/__init__.py @@ -2,7 +2,7 @@ from .models import ConnectionCredentials, ConnectionItem, DatasourceItem,\ GroupItem, PaginationItem, ProjectItem, ScheduleItem, \ SiteItem, TableauAuth, UserItem, ViewItem, WorkbookItem, UnpopulatedPropertyError, \ - HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval, IntervalItem , TaskItem + HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval, IntervalItem, TaskItem from .server import RequestOptions, ImageRequestOptions, Filter, Sort, Server, ServerResponseError,\ MissingRequiredFieldError, NotSignedInError, Pager diff --git a/tableauserverclient/models/task_item.py b/tableauserverclient/models/task_item.py index f41ca04ba..742a9eaa0 100644 --- a/tableauserverclient/models/task_item.py +++ b/tableauserverclient/models/task_item.py @@ -13,8 +13,7 @@ def __init__(self, id_, task_type, priority, consecutive_failed_count=0, schedul def __repr__(self): return "".format( - **self.__dict__) + "schedule_id})>".format(**self.__dict__) @classmethod def from_response(cls, xml): @@ -35,4 +34,4 @@ def _parse_task(cls, element): priority = int(element.get('priority', -1)) consecutive_failed_count = int(element.get('consecutiveFailedCount', 0)) id_ = element.get('id', None) - return cls(id_, task_type, priority, consecutive_failed_count, schedule) \ No newline at end of file + return cls(id_, task_type, priority, consecutive_failed_count, schedule) From d28603081b41dc004ec14c78b976eef8158b9151 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Tue, 21 Feb 2017 12:29:00 -0800 Subject: [PATCH 07/12] Correct the path to extract refresh tasks --- tableauserverclient/models/task_item.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tableauserverclient/models/task_item.py b/tableauserverclient/models/task_item.py index 742a9eaa0..f304704b8 100644 --- a/tableauserverclient/models/task_item.py +++ b/tableauserverclient/models/task_item.py @@ -18,7 +18,8 @@ def __repr__(self): @classmethod def from_response(cls, xml): parsed_response = ET.fromstring(xml) - all_tasks_xml = parsed_response.findall('.//t:task', namespaces=NAMESPACE) + all_tasks_xml = parsed_response.findall( + './/t:task/t:extractRefresh', namespaces=NAMESPACE) all_tasks = (TaskItem._parse_task(x) for x in all_tasks_xml) From 9bd8e6fa0111f4a139c86e70025b9ef51f43cdcb Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Tue, 21 Feb 2017 12:37:59 -0800 Subject: [PATCH 08/12] fixing missed pep8 failure --- tableauserverclient/server/request_options.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tableauserverclient/server/request_options.py b/tableauserverclient/server/request_options.py index 876363544..acd82c68e 100644 --- a/tableauserverclient/server/request_options.py +++ b/tableauserverclient/server/request_options.py @@ -76,6 +76,7 @@ def apply_query_params(self, url): return "{0}?{1}".format(url, '&'.join(params)) + class ImageRequestOptions(RequestOptionsBase): # if 'high' isn't specified, the REST API endpoint returns an image with standard resolution class Resolution: From 8516bdb871f7150afeacd7fb66bb9300c0bbc582 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Thu, 23 Mar 2017 13:15:08 -0700 Subject: [PATCH 09/12] adding runNow to the interface --- samples/refresh_tasks.py | 49 ++++++++++++++----- .../server/endpoint/tasks_endpoint.py | 18 +++++-- tableauserverclient/server/request_factory.py | 17 +++++++ 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/samples/refresh_tasks.py b/samples/refresh_tasks.py index 9c6bf6196..51e20c968 100644 --- a/samples/refresh_tasks.py +++ b/samples/refresh_tasks.py @@ -9,19 +9,51 @@ import tableauserverclient as TSC -def main(): +def handle_run(server, args): + task = server.tasks.get_by_id(args.id) + print(server.tasks.run(task)) + + +def handle_list(server, _): + tasks, pagination = server.tasks.get() + for task in tasks: + print("{}".format(task)) + + +def handle_info(server, args): + task = server.tasks.get_by_id(args.id) + print("{}".format(task)) + +def main(): parser = argparse.ArgumentParser(description='Get all of the refresh tasks available on a server') parser.add_argument('--server', '-s', required=True, help='server address') parser.add_argument('--username', '-u', required=True, help='username to sign into server') parser.add_argument('--site', '-S', default=None) - parser.add_argument('--id', '-i', default=None) + parser.add_argument('-p', default=None) + parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error', help='desired logging level (set to error by default)') + subcommands = parser.add_subparsers() + + list_arguments = subcommands.add_parser('list') + list_arguments.set_defaults(func=handle_list) + + run_arguments = subcommands.add_parser('run') + run_arguments.add_argument('id', default=None) + run_arguments.set_defaults(func=handle_run) + + info_arguments = subcommands.add_parser('info') + info_arguments.add_argument('id', default=None) + info_arguments.set_defaults(func=handle_info) + args = parser.parse_args() - password = getpass.getpass("Password: ") + if args.p is None: + password = getpass.getpass("Password: ") + else: + password = args.p # Set logging level based on user input, or error by default logging_level = getattr(logging, args.logging_level.upper()) @@ -30,16 +62,9 @@ def main(): # SIGN IN tableau_auth = TSC.TableauAuth(args.username, password, args.site) server = TSC.Server(args.server) - server.version = '2.5' + server.version = '2.6' with server.auth.sign_in(tableau_auth): - import pprint - - if args.id: - task = server.tasks.get_by_id(args.id) - pprint.pprint(task) - else: - tasks, pagination = server.tasks.get() - pprint.pprint(tasks) + args.func(server, args) if __name__ == '__main__': diff --git a/tableauserverclient/server/endpoint/tasks_endpoint.py b/tableauserverclient/server/endpoint/tasks_endpoint.py index 92f7eb7e3..81297edb4 100644 --- a/tableauserverclient/server/endpoint/tasks_endpoint.py +++ b/tableauserverclient/server/endpoint/tasks_endpoint.py @@ -1,5 +1,6 @@ from .endpoint import Endpoint -from .. import TaskItem, PaginationItem +from .exceptions import MissingRequiredFieldError +from .. import TaskItem, PaginationItem, RequestFactory import logging logger = logging.getLogger('tableau.endpoint.tasks') @@ -8,8 +9,8 @@ class Tasks(Endpoint): @property def baseurl(self): - return "{0}/sites/{1}/tasks/extract-refreshes".format(self.parent_srv.baseurl, - self.parent_srv.site_id) + return "{0}/sites/{1}/tasks/extractRefreshes".format(self.parent_srv.baseurl, + self.parent_srv.site_id) def get(self, req_options=None): logger.info('Querying all tasks for the site') @@ -28,3 +29,14 @@ def get_by_id(self, task_id): url = "{}/{}".format(self.baseurl, task_id) server_response = self.get_request(url) return TaskItem.from_response(server_response.content)[0] + + def run(self, task_item): + if not task_item.id: + error = "User item missing ID." + raise MissingRequiredFieldError(error) + + url = "{0}/{1}/runNow".format(self.baseurl, task_item.id) + print(url) + run_req = RequestFactory.Task.run_req(task_item) + server_response = self.post_request(url, run_req) + return server_response.content \ No newline at end of file diff --git a/tableauserverclient/server/request_factory.py b/tableauserverclient/server/request_factory.py index 25d89ce15..439f517cb 100644 --- a/tableauserverclient/server/request_factory.py +++ b/tableauserverclient/server/request_factory.py @@ -1,5 +1,6 @@ from ..datetime_helpers import format_datetime import xml.etree.ElementTree as ET +from functools import wraps from requests.packages.urllib3.fields import RequestField from requests.packages.urllib3.filepost import encode_multipart_formdata @@ -16,6 +17,14 @@ def _add_multipart(parts): return xml_request, content_type +def _tsrequest_wrapped(func): + def wrapper(self, *args, **kwargs): + xml_request = ET.Element('tsRequest') + func(xml_request, *args, **kwargs) + return ET.tostring(xml_request) + return wrapper + + class AuthRequest(object): def signin_req(self, auth_item): xml_request = ET.Element('tsRequest') @@ -331,6 +340,13 @@ def update_req(self, connection_item): return ET.tostring(xml_request) +class TaskRequest(object): + @_tsrequest_wrapped + def run_req(xml_request, task_item): + # Send an empty tsRequest + pass + + class RequestFactory(object): Auth = AuthRequest() Datasource = DatasourceRequest() @@ -341,6 +357,7 @@ class RequestFactory(object): Schedule = ScheduleRequest() Site = SiteRequest() Tag = TagRequest() + Task = TaskRequest() User = UserRequest() Workbook = WorkbookRequest() WorkbookConnection = WorkbookConnection() From 8c9caf4de09aeb26b4ca31e3e834186044d97c56 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Thu, 23 Mar 2017 13:40:42 -0700 Subject: [PATCH 10/12] fixing pep8 issues --- tableauserverclient/server/endpoint/tasks_endpoint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tableauserverclient/server/endpoint/tasks_endpoint.py b/tableauserverclient/server/endpoint/tasks_endpoint.py index 81297edb4..5d884ab4b 100644 --- a/tableauserverclient/server/endpoint/tasks_endpoint.py +++ b/tableauserverclient/server/endpoint/tasks_endpoint.py @@ -39,4 +39,4 @@ def run(self, task_item): print(url) run_req = RequestFactory.Task.run_req(task_item) server_response = self.post_request(url, run_req) - return server_response.content \ No newline at end of file + return server_response.content From 89589f52f250daec60dee23e2149e0cdf7bd0044 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Thu, 23 Mar 2017 14:02:55 -0700 Subject: [PATCH 11/12] Add header documentation to the sample. --- samples/refresh_tasks.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/refresh_tasks.py b/samples/refresh_tasks.py index 51e20c968..214a2131b 100644 --- a/samples/refresh_tasks.py +++ b/samples/refresh_tasks.py @@ -1,5 +1,8 @@ #### -# TODO +# This script demonstrates how to use the Tableau Server Client +# to query extract refresh tasks and run them as needed. +# +# To run the script, you must have installed Python 2.7.X or 3.3 and later. #### import argparse From 864a51b2923f0f3b30f6c63b6a028019bed8cc32 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Fri, 24 Mar 2017 14:10:27 -0700 Subject: [PATCH 12/12] addressing tyler's feedback --- tableauserverclient/models/schedule_item.py | 1 - tableauserverclient/models/task_item.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tableauserverclient/models/schedule_item.py b/tableauserverclient/models/schedule_item.py index f22fd0d48..f84f726e4 100644 --- a/tableauserverclient/models/schedule_item.py +++ b/tableauserverclient/models/schedule_item.py @@ -34,7 +34,6 @@ def __init__(self, name, priority, schedule_type, execution_order, interval_item self.schedule_type = schedule_type def __repr__(self): - print(self.__dict__) return "".format(**self.__dict__) @property diff --git a/tableauserverclient/models/task_item.py b/tableauserverclient/models/task_item.py index f304704b8..b87c0eaa6 100644 --- a/tableauserverclient/models/task_item.py +++ b/tableauserverclient/models/task_item.py @@ -21,12 +21,12 @@ def from_response(cls, xml): all_tasks_xml = parsed_response.findall( './/t:task/t:extractRefresh', namespaces=NAMESPACE) - all_tasks = (TaskItem._parse_task(x) for x in all_tasks_xml) + all_tasks = (TaskItem._parse_element(x) for x in all_tasks_xml) return list(all_tasks) @classmethod - def _parse_task(cls, element): + def _parse_element(cls, element): schedule = None schedule_element = element.find('.//t:schedule', namespaces=NAMESPACE) if schedule_element is not None: