Add workbook to tasks#206
Add workbook to tasks#206t8y8 merged 8 commits intotableau:developmenttableau/server-client-python:developmentfrom williamlang:add-workbook-to-taskswilliamlang/server-client-python:add-workbook-to-tasksCopy head branch name to clipboard
Conversation
|
@williamlang is a Tableau employee for those who may not know :) I'm not super familiar with the Tasks APIs... when does it include a workbook id? It looks like it could in theory contain a data source as well -- which means we'd want a datasource_id as well OR an 'object_id' and 'object_type' that we handle for the user I'll take a look at the code in a bit, I reserve the right to propose an alternative ;) |
t8y8
left a comment
There was a problem hiding this comment.
The code LGTM.
Still thinking about the API...
|
@t8y8 you are right though, the second example response does include a datasource id. |
|
@t8y8 @benlower @RussTheAerialist Here are a few scenarios of how we could incorporate workbook_id and datasource_id |
|
I think the dict case might be the cleanest API: for task in all_tasks:
if task.content['type'] == 'workbook': # Note that dot notation doesn't work for dicts in python
print(task.content['id'])Or wb_tasks = filter(lambda t: t.content.get('type') == 'workbook', all_tasks)This is actually a pattern we have to solve for permissions APIs. I slightly prefer the dict but I'm also ok with option 1, simply having a datasource_id AND a workbook_id attribute, and maybe some setter magic to make sure both are never set. |
|
Hey @williamlang - @t8y8 and I talked about the various approaches outlined. I'm not super keen on any of the three as outlined, but I think merging the ideas of 2 and 3 into a 4th option would be the way I'd like to see it happen. If we had a class called Target with a type and id attribute, then we'd get the ease of use of 3 with the slightly stronger type of 2 without polluting the Task object with prefixed attributes (e.g. Does that make sense? |
|
@RussTheAerialist @t8y8 is this what you're thinking? |
tableauserverclient/models/target.py
Outdated
| def __repr__(self): | ||
| return "<Target#{id}, {target_type}>" | ||
|
|
||
| def get_type(self): |
There was a problem hiding this comment.
Ahh Java snuck into your Python code ;)
+class Target():
def __init__(self, id, target_type):
self.id = id
self.target_type = target_type
@property
def target_type(self):
return self.target_type
Or you can just leave them as attributes without any protection since the object is very simple:
class Target(object):
def __init__(...):
self.id = id_
self.target_type = target_type
def __repr__(self):
...
There was a problem hiding this comment.
Or, if we go with type:
class Target(object):
def __init__(self, id_, target_type)
self.id = id_
self.type = target_type
@property
def type(self):
return self.typeThere was a problem hiding this comment.
I think I'm more of a fan of type rather than target_type because Target is already included in the name of the class, so it ends up being redundant.
tableauserverclient/models/target.py
Outdated
| @@ -0,0 +1,14 @@ | ||
| """Target class meant to abstract mappings to other objects""" | ||
| class Target(): | ||
| def __init__(self, id, target_type): |
There was a problem hiding this comment.
Name the function parameter id_ to avoid collision with the built in.
tableauserverclient/models/target.py
Outdated
| @@ -0,0 +1,14 @@ | ||
| """Target class meant to abstract mappings to other objects""" | ||
| class Target(): |
There was a problem hiding this comment.
Two blank lines here (between docstring and the class def) should fix the style checker
tableauserverclient/models/target.py:2:1: E302 expected 2 blank lines, found 0
tableauserverclient/models/target.py
Outdated
| self.target_type = target_type | ||
|
|
||
| def __repr__(self): | ||
| return "<Target#{id}, {target_type}>" |
There was a problem hiding this comment.
I think you'll need a .format(**self) at the end of the repr.
| self.task_type = task_type | ||
| self.priority = priority | ||
| self.consecutive_failed_count = consecutive_failed_count | ||
| self.schedule_id = schedule_id |
There was a problem hiding this comment.
Why was this line removed?
|
@RussTheAerialist added a test to prevent schedule_id getting deleted again :) @t8y8 did the thing. |
| if datasource_element is not None: | ||
| datasource_id = datasource_element.get('id', None) | ||
| target = Target(datasource_id, "datasource") | ||
| # |
There was a problem hiding this comment.
Remove this extra '#' and the space around it (of course still making the style checker happy)
| self.assertEqual('c7a9327e-1cda-4504-b026-ddb43b976d1d', task.target.id) | ||
| self.assertEqual('datasource', task.target.type) | ||
|
|
||
| def test_get_tasks_with_workbook_and_datasource(self): |
There was a problem hiding this comment.
This is technically never possible, right? (though a test for it is fine -- we may do this someday)
|
🚀🚀 |
According to the docs here:
https://onlinehelp.tableau.com/current/api/rest_api/en-us/help.htm#REST/rest_api_ref.htm#Query_Extract_Refresh_Tasks%3FTocPath%3DAPI%2520Reference%7C_____57
Tasks may or may not have a workbook tag. Added support for this.