Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions tableauserverclient/models/job_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def __init__(
finish_code: int = 0,
notes: Optional[List[str]] = None,
mode: Optional[str] = None,
workbook_id: Optional[str] = None,
datasource_id: Optional[str] = None,
flow_run: Optional[FlowRunItem] = None,
):
self._id = id_
Expand All @@ -42,6 +44,8 @@ def __init__(
self._finish_code = finish_code
self._notes: List[str] = notes or []
self._mode = mode
self._workbook_id = workbook_id
self._datasource_id = datasource_id
self._flow_run = flow_run

@property
Expand Down Expand Up @@ -85,6 +89,22 @@ def mode(self, value: str) -> None:
# check for valid data here
self._mode = value

@property
def workbook_id(self) -> Optional[str]:
return self._workbook_id

@workbook_id.setter
def workbook_id(self, value: Optional[str]) -> None:
self._workbook_id = value

@property
def datasource_id(self) -> Optional[str]:
return self._datasource_id

@datasource_id.setter
def datasource_id(self, value: Optional[str]) -> None:
self._datasource_id = value

@property
def flow_run(self):
return self._flow_run
Expand Down Expand Up @@ -119,6 +139,10 @@ def _parse_element(cls, element, ns):
finish_code = int(element.get("finishCode", -1))
notes = [note.text for note in element.findall(".//t:notes", namespaces=ns)] or None
mode = element.get("mode", None)
workbook = element.find(".//t:workbook[@id]", namespaces=ns)
workbook_id = workbook.get("id") if workbook is not None else None
datasource = element.find(".//t:datasource[@id]", namespaces=ns)
datasource_id = datasource.get("id") if datasource is not None else None
flow_run = None
for flow_job in element.findall(".//t:runFlowJobType", namespaces=ns):
flow_run = FlowRunItem()
Expand All @@ -136,6 +160,8 @@ def _parse_element(cls, element, ns):
finish_code,
notes,
mode,
workbook_id,
datasource_id,
flow_run,
)

Expand Down
9 changes: 9 additions & 0 deletions test/assets/job_get_by_id_failed_workbook.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version='1.0' encoding='UTF-8'?>
<tsResponse xmlns="http://tableau.com/api" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://tableau.com/api https://help.tableau.com/samples/en-us/rest_api/ts-api_3_14.xsd">
<job id="bb1aab79-db54-4e96-9dd3-461d8f081d08" mode="Asynchronous" type="RefreshExtract" progress="100" createdAt="2021-10-05T18:53:34Z" startedAt="2021-10-05T18:53:34Z" completedAt="2021-10-05T18:53:35Z" finishCode="1">
<extractRefreshJob>
<workbook id="5998aaaf-1abe-4d38-b4d9-bc53e85bdd13" name="Superstore"/>
<notes>java.lang.RuntimeException: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Login failed for user.\nIntegrated authentication failed.</notes>
</extractRefreshJob>
</job>
</tsResponse>
19 changes: 17 additions & 2 deletions test/test_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@
from tableauserverclient.server.endpoint.exceptions import JobFailedException
from ._utils import read_xml_asset, mocked_time

TEST_ASSET_DIR = os.path.join(os.path.dirname(__file__), "assets")

GET_XML = "job_get.xml"
GET_BY_ID_XML = "job_get_by_id.xml"
GET_BY_ID_FAILED_XML = "job_get_by_id_failed.xml"
GET_BY_ID_CANCELLED_XML = "job_get_by_id_cancelled.xml"
GET_BY_ID_INPROGRESS_XML = "job_get_by_id_inprogress.xml"
GET_BY_ID_WORKBOOK = "job_get_by_id_failed_workbook.xml"


class JobTests(unittest.TestCase):
Expand Down Expand Up @@ -103,3 +102,19 @@ def test_wait_for_job_timeout(self) -> None:
m.get("{0}/{1}".format(self.baseurl, job_id), text=response_xml)
with self.assertRaises(TimeoutError):
self.server.jobs.wait_for_job(job_id, timeout=30)

def test_get_job_datasource_id(self) -> None:
response_xml = read_xml_asset(GET_BY_ID_FAILED_XML)
job_id = "777bf7c4-421d-4b2c-a518-11b90187c545"
with requests_mock.mock() as m:
m.get(f"{self.baseurl}/{job_id}", text=response_xml)
job = self.server.jobs.get_by_id(job_id)
self.assertEqual(job.datasource_id, "03b9fbec-81f6-4160-ae49-5f9f6d412758")

def test_get_job_workbook_id(self) -> None:
response_xml = read_xml_asset(GET_BY_ID_WORKBOOK)
job_id = "bb1aab79-db54-4e96-9dd3-461d8f081d08"
with requests_mock.mock() as m:
m.get(f"{self.baseurl}/{job_id}", text=response_xml)
job = self.server.jobs.get_by_id(job_id)
self.assertEqual(job.workbook_id, "5998aaaf-1abe-4d38-b4d9-bc53e85bdd13")