Skip to content

Commit b81993a

Browse files
authored
Adding incremental refresh option for workbook and datasource endpoints along with the new JobItem code changes (#1585)
* Adding incremental refresh option to workbook and datasource along with new job item finish code * Fix build pipeline failures related to mypy & black
1 parent ba716b9 commit b81993a

File tree

8 files changed

+89
-9
lines changed

8 files changed

+89
-9
lines changed

tableauserverclient/models/job_item.py

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class FinishCode:
8282
Success: int = 0
8383
Failed: int = 1
8484
Cancelled: int = 2
85+
Completed: int = 3
8586

8687
def __init__(
8788
self,

tableauserverclient/server/endpoint/datasources_endpoint.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,7 @@ def refresh(self, datasource_item: DatasourceItem, incremental: bool = False) ->
340340
"""
341341
id_ = getattr(datasource_item, "id", datasource_item)
342342
url = f"{self.baseurl}/{id_}/refresh"
343-
# refresh_req = RequestFactory.Task.refresh_req(incremental)
344-
refresh_req = RequestFactory.Empty.empty_req()
343+
refresh_req = RequestFactory.Task.refresh_req(incremental, self.parent_srv)
345344
server_response = self.post_request(url, refresh_req)
346345
new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
347346
return new_job

tableauserverclient/server/endpoint/jobs_endpoint.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def wait_for_job(self, job_id: Union[str, JobItem], *, timeout: Optional[float]
188188

189189
logger.info(f"Job {job_id} Completed: Finish Code: {job.finish_code} - Notes:{job.notes}")
190190

191-
if job.finish_code == JobItem.FinishCode.Success:
191+
if job.finish_code in [JobItem.FinishCode.Success, JobItem.FinishCode.Completed]:
192192
return job
193193
elif job.finish_code == JobItem.FinishCode.Failed:
194194
raise JobFailedException(job)

tableauserverclient/server/endpoint/workbooks_endpoint.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def refresh(self, workbook_item: Union[WorkbookItem, str], incremental: bool = F
140140
"""
141141
id_ = getattr(workbook_item, "id", workbook_item)
142142
url = f"{self.baseurl}/{id_}/refresh"
143-
refresh_req = RequestFactory.Task.refresh_req(incremental)
143+
refresh_req = RequestFactory.Task.refresh_req(incremental, self.parent_srv)
144144
server_response = self.post_request(url, refresh_req)
145145
new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
146146
return new_job

tableauserverclient/server/request_factory.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -1118,11 +1118,17 @@ def run_req(self, xml_request: ET.Element, task_item: Any) -> None:
11181118
pass
11191119

11201120
@_tsrequest_wrapped
1121-
def refresh_req(self, xml_request: ET.Element, incremental: bool = False) -> bytes:
1122-
task_element = ET.SubElement(xml_request, "extractRefresh")
1123-
if incremental:
1124-
task_element.attrib["incremental"] = "true"
1125-
return ET.tostring(xml_request)
1121+
def refresh_req(
1122+
self, xml_request: ET.Element, incremental: bool = False, parent_srv: Optional["Server"] = None
1123+
) -> Optional[bytes]:
1124+
if parent_srv is not None and parent_srv.check_at_least_version("3.25"):
1125+
task_element = ET.SubElement(xml_request, "extractRefresh")
1126+
if incremental:
1127+
task_element.attrib["incremental"] = "true"
1128+
return ET.tostring(xml_request)
1129+
elif incremental:
1130+
raise ValueError("Incremental refresh is only supported in 3.25+")
1131+
return None
11261132

11271133
@_tsrequest_wrapped
11281134
def create_extract_req(self, xml_request: ET.Element, extract_item: "TaskItem") -> bytes:
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<tsResponse xmlns="http://tableau.com/api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://tableau.com/api http://tableau.com/api/ts-api-3.1.xsd">
4+
<job id="2eef4225-aa0c-41c4-8662-a76d89ed7336" mode="job-mode" type="extractRefreshJob"
5+
progress="100" createdAt="2020-05-13T20:23:45Z" updatedAt="2020-05-13T20:25:18Z"
6+
completedAt="2020-05-13T20:25:18Z" finishCode="3">
7+
<extractRefreshJob>
8+
<notes>Job detail notes</notes>
9+
</extractRefreshJob>
10+
<statusNotes>
11+
<statusNote type="CountOfUsersAddedToGroup" value="5" text="Description of how many users were added to the group during the import." />More detail
12+
</statusNotes>
13+
</job>
14+
</tsResponse>
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import unittest
2+
import xml.etree.ElementTree as ET
3+
from unittest.mock import Mock
4+
from tableauserverclient.server.request_factory import TaskRequest
5+
6+
7+
class TestTaskRequest(unittest.TestCase):
8+
9+
def setUp(self):
10+
self.task_request = TaskRequest()
11+
self.xml_request = ET.Element("tsRequest")
12+
13+
def test_refresh_req_default(self):
14+
result = self.task_request.refresh_req()
15+
self.assertEqual(result, ET.tostring(self.xml_request))
16+
17+
def test_refresh_req_incremental(self):
18+
with self.assertRaises(ValueError):
19+
self.task_request.refresh_req(incremental=True)
20+
21+
def test_refresh_req_with_parent_srv_version_3_25(self):
22+
parent_srv = Mock()
23+
parent_srv.check_at_least_version.return_value = True
24+
result = self.task_request.refresh_req(incremental=True, parent_srv=parent_srv)
25+
expected_xml = ET.Element("tsRequest")
26+
task_element = ET.SubElement(expected_xml, "extractRefresh")
27+
task_element.attrib["incremental"] = "true"
28+
self.assertEqual(result, ET.tostring(expected_xml))
29+
30+
def test_refresh_req_with_parent_srv_version_3_25_non_incremental(self):
31+
parent_srv = Mock()
32+
parent_srv.check_at_least_version.return_value = True
33+
result = self.task_request.refresh_req(incremental=False, parent_srv=parent_srv)
34+
expected_xml = ET.Element("tsRequest")
35+
ET.SubElement(expected_xml, "extractRefresh")
36+
self.assertEqual(result, ET.tostring(expected_xml))
37+
38+
def test_refresh_req_with_parent_srv_version_below_3_25(self):
39+
parent_srv = Mock()
40+
parent_srv.check_at_least_version.return_value = False
41+
with self.assertRaises(ValueError):
42+
self.task_request.refresh_req(incremental=True, parent_srv=parent_srv)
43+
44+
def test_refresh_req_with_parent_srv_version_below_3_25_non_incremental(self):
45+
parent_srv = Mock()
46+
parent_srv.check_at_least_version.return_value = False
47+
result = self.task_request.refresh_req(incremental=False, parent_srv=parent_srv)
48+
self.assertEqual(result, ET.tostring(self.xml_request))

test/test_job.py

+12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
GET_XML = "job_get.xml"
1313
GET_BY_ID_XML = "job_get_by_id.xml"
14+
GET_BY_ID_COMPLETED_XML = "job_get_by_id_completed.xml"
1415
GET_BY_ID_FAILED_XML = "job_get_by_id_failed.xml"
1516
GET_BY_ID_CANCELLED_XML = "job_get_by_id_cancelled.xml"
1617
GET_BY_ID_INPROGRESS_XML = "job_get_by_id_inprogress.xml"
@@ -87,6 +88,17 @@ def test_wait_for_job_finished(self) -> None:
8788
self.assertEqual(job_id, job.id)
8889
self.assertListEqual(job.notes, ["Job detail notes"])
8990

91+
def test_wait_for_job_completed(self) -> None:
92+
# Waiting for a bridge (cloud) job completion
93+
response_xml = read_xml_asset(GET_BY_ID_COMPLETED_XML)
94+
job_id = "2eef4225-aa0c-41c4-8662-a76d89ed7336"
95+
with mocked_time(), requests_mock.mock() as m:
96+
m.get(f"{self.baseurl}/{job_id}", text=response_xml)
97+
job = self.server.jobs.wait_for_job(job_id)
98+
99+
self.assertEqual(job_id, job.id)
100+
self.assertListEqual(job.notes, ["Job detail notes"])
101+
90102
def test_wait_for_job_failed(self) -> None:
91103
# Waiting for a failed job raises an exception
92104
response_xml = read_xml_asset(GET_BY_ID_FAILED_XML)

0 commit comments

Comments
 (0)