diff --git a/tableauserverclient/models/schedule_item.py b/tableauserverclient/models/schedule_item.py
index 94823d6c2..5ece2f8fe 100644
--- a/tableauserverclient/models/schedule_item.py
+++ b/tableauserverclient/models/schedule_item.py
@@ -162,10 +162,7 @@ def from_response(cls, resp, ns):
@classmethod
def from_element(cls, parsed_response, ns):
- all_warning_xml = parsed_response.findall('.//t:warning', namespaces=ns)
- warnings = list() if len(all_warning_xml) > 0 else None
- for warning_xml in all_warning_xml:
- warnings.append(warning_xml.get('message', None))
+ warnings = cls._read_warnings(parsed_response, ns)
all_schedule_items = []
all_schedule_xml = parsed_response.findall('.//t:schedule', namespaces=ns)
@@ -248,3 +245,22 @@ def _parse_element(schedule_xml, ns):
return id, name, state, created_at, updated_at, schedule_type, \
next_run_at, end_schedule_at, execution_order, priority, interval_item
+
+ @staticmethod
+ def parse_add_to_schedule_response(response, ns):
+ parsed_response = ET.fromstring(response.content)
+ warnings = ScheduleItem._read_warnings(parsed_response, ns)
+ all_task_xml = parsed_response.findall('.//t:task', namespaces=ns)
+
+ error = "Status {}: {}".format(response.status_code, response.reason) \
+ if response.status_code < 200 or response.status_code >= 300 else None
+ task_created = len(all_task_xml) > 0
+ return error, warnings, task_created
+
+ @staticmethod
+ def _read_warnings(parsed_response, ns):
+ all_warning_xml = parsed_response.findall('.//t:warning', namespaces=ns)
+ warnings = list() if len(all_warning_xml) > 0 else None
+ for warning_xml in all_warning_xml:
+ warnings.append(warning_xml.get('message', None))
+ return warnings
diff --git a/tableauserverclient/server/endpoint/schedules_endpoint.py b/tableauserverclient/server/endpoint/schedules_endpoint.py
index ccba83565..06fb7e408 100644
--- a/tableauserverclient/server/endpoint/schedules_endpoint.py
+++ b/tableauserverclient/server/endpoint/schedules_endpoint.py
@@ -7,8 +7,8 @@
logger = logging.getLogger('tableau.endpoint.schedules')
# Oh to have a first class Result concept in Python...
-AddResponse = namedtuple('AddResponse', ('result', 'error'))
-OK = AddResponse(result=True, error=None)
+AddResponse = namedtuple('AddResponse', ('result', 'error', 'warnings', 'task_created'))
+OK = AddResponse(result=True, error=None, warnings=None, task_created=None)
class Schedules(Endpoint):
@@ -70,17 +70,21 @@ def create(self, schedule_item):
@api(version="2.8")
def add_to_schedule(self, schedule_id, workbook=None, datasource=None,
task_type=TaskItem.Type.ExtractRefresh):
-
def add_to(resource, type_, req_factory):
id_ = resource.id
url = "{0}/{1}/{2}s".format(self.siteurl, schedule_id, type_)
add_req = req_factory(id_, task_type=task_type)
response = self.put_request(url, add_req)
- if response.status_code < 200 or response.status_code >= 300:
- return AddResponse(result=False,
- error="Status {}: {}".format(response.status_code, response.reason))
- logger.info("Added {} to {} to schedule {}".format(type_, id_, schedule_id))
- return OK
+
+ error, warnings, task_created = ScheduleItem.parse_add_to_schedule_response(
+ response, self.parent_srv.namespace)
+ if task_created:
+ logger.info("Added {} to {} to schedule {}".format(type_, id_, schedule_id))
+
+ if error is not None or warnings is not None:
+ return AddResponse(result=False, error=error, warnings=warnings, task_created=task_created)
+ else:
+ return OK
items = []
diff --git a/test/assets/schedule_add_datasource.xml b/test/assets/schedule_add_datasource.xml
new file mode 100644
index 000000000..e57d2c8d2
--- /dev/null
+++ b/test/assets/schedule_add_datasource.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/assets/schedule_add_workbook.xml b/test/assets/schedule_add_workbook.xml
new file mode 100644
index 000000000..a6adb005e
--- /dev/null
+++ b/test/assets/schedule_add_workbook.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/assets/schedule_add_workbook_with_warnings.xml b/test/assets/schedule_add_workbook_with_warnings.xml
new file mode 100644
index 000000000..0c376d018
--- /dev/null
+++ b/test/assets/schedule_add_workbook_with_warnings.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/test_schedule.py b/test/test_schedule.py
index 310a2b84a..b7b047d02 100644
--- a/test/test_schedule.py
+++ b/test/test_schedule.py
@@ -14,6 +14,9 @@
CREATE_WEEKLY_XML = os.path.join(TEST_ASSET_DIR, "schedule_create_weekly.xml")
CREATE_MONTHLY_XML = os.path.join(TEST_ASSET_DIR, "schedule_create_monthly.xml")
UPDATE_XML = os.path.join(TEST_ASSET_DIR, "schedule_update.xml")
+ADD_WORKBOOK_TO_SCHEDULE = os.path.join(TEST_ASSET_DIR, "schedule_add_workbook.xml")
+ADD_WORKBOOK_TO_SCHEDULE_WITH_WARNINGS = os.path.join(TEST_ASSET_DIR, "schedule_add_workbook_with_warnings.xml")
+ADD_DATASOURCE_TO_SCHEDULE = os.path.join(TEST_ASSET_DIR, "schedule_add_datasource.xml")
WORKBOOK_GET_BY_ID_XML = os.path.join(TEST_ASSET_DIR, 'workbook_get_by_id.xml')
DATASOURCE_GET_BY_ID_XML = os.path.join(TEST_ASSET_DIR, 'datasource_get_by_id.xml')
@@ -208,24 +211,42 @@ def test_add_workbook(self):
with open(WORKBOOK_GET_BY_ID_XML, "rb") as f:
workbook_response = f.read().decode("utf-8")
+ with open(ADD_WORKBOOK_TO_SCHEDULE, "rb") as f:
+ add_workbook_response = f.read().decode("utf-8")
with requests_mock.mock() as m:
- # TODO: Replace with real response
m.get(self.server.workbooks.baseurl + '/bar', text=workbook_response)
- m.put(baseurl + '/foo/workbooks', text="OK")
+ m.put(baseurl + '/foo/workbooks', text=add_workbook_response)
workbook = self.server.workbooks.get_by_id("bar")
result = self.server.schedules.add_to_schedule('foo', workbook=workbook)
self.assertEqual(0, len(result), "Added properly")
+ def test_add_workbook_with_warnings(self):
+ self.server.version = "2.8"
+ baseurl = "{}/sites/{}/schedules".format(self.server.baseurl, self.server.site_id)
+
+ with open(WORKBOOK_GET_BY_ID_XML, "rb") as f:
+ workbook_response = f.read().decode("utf-8")
+ with open(ADD_WORKBOOK_TO_SCHEDULE_WITH_WARNINGS, "rb") as f:
+ add_workbook_response = f.read().decode("utf-8")
+ with requests_mock.mock() as m:
+ m.get(self.server.workbooks.baseurl + '/bar', text=workbook_response)
+ m.put(baseurl + '/foo/workbooks', text=add_workbook_response)
+ workbook = self.server.workbooks.get_by_id("bar")
+ result = self.server.schedules.add_to_schedule('foo', workbook=workbook)
+ self.assertEqual(1, len(result), "Not added properly")
+ self.assertEqual(2, len(result[0].warnings))
+
def test_add_datasource(self):
self.server.version = "2.8"
baseurl = "{}/sites/{}/schedules".format(self.server.baseurl, self.server.site_id)
with open(DATASOURCE_GET_BY_ID_XML, "rb") as f:
datasource_response = f.read().decode("utf-8")
+ with open(ADD_DATASOURCE_TO_SCHEDULE, "rb") as f:
+ add_datasource_response = f.read().decode("utf-8")
with requests_mock.mock() as m:
- # TODO: Replace with real response
m.get(self.server.datasources.baseurl + '/bar', text=datasource_response)
- m.put(baseurl + '/foo/datasources', text="OK")
+ m.put(baseurl + '/foo/datasources', text=add_datasource_response)
datasource = self.server.datasources.get_by_id("bar")
result = self.server.schedules.add_to_schedule('foo', datasource=datasource)
self.assertEqual(0, len(result), "Added properly")