Skip to content

Add workbook to tasks#206

Merged
t8y8 merged 8 commits intotableau:developmentfrom
williamlang:add-workbook-to-tasks
Jul 20, 2017
Merged

Add workbook to tasks#206
t8y8 merged 8 commits intotableau:developmentfrom
williamlang:add-workbook-to-tasks

Conversation

@williamlang
Copy link

@t8y8
Copy link
Collaborator

t8y8 commented Jul 13, 2017

@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 ;)

Copy link
Collaborator

@t8y8 t8y8 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code LGTM.

Still thinking about the API...

@williamlang
Copy link
Author

@t8y8 you are right though, the second example response does include a datasource id.

@williamlang
Copy link
Author

@t8y8 @benlower @RussTheAerialist

Here are a few scenarios of how we could incorporate workbook_id and datasource_id

        # case 1: workbook_id and datasource_id
        workbook_tasks = [[task.id, task.schedule_id, task.workbook_id] for task in all_tasks]
        datasource_taks = [[task.id, task.schedule_id, task.datasource_id] for task in all_tasks]

        for workbook_task in workbook_tasks:
            server.workbooks.get(workbook_task.workbook_id)

        for datasource_task in datasource_taks:
            server.datasources.get(datasource_task.datasource_id)

        # case 2: object_name
        workbook_tasks = filter(lambda task : task.object_name == 'workbook', all_tasks)
        datasource_tasks = filter(lambda task : task.object_name == 'datasource', all_tasks)

        # case 2b: object_name
        for task in all_tasks:
            if task.object_name == 'workbook':
                server.workbooks.get(task.object_id)
            else if task.object_name == 'datasource':
                server.datasources.get(task.object_id)

        # case 3: hash map
        workbook_tasks = filter(lambda task : task.content.type == 'workbook', all_tasks)
        datasource_tasks = filter(lambda task : task.content.type == 'datasource', all_tasks)

        # case 3b: hash_map
        for task in all_tasks:
            if task.content.type == 'workbook':
                server.workbooks.get(task.content.id)
            else if task.content.type == 'datasource':
                server.datasources.get(task.content.id)`

@t8y8
Copy link
Collaborator

t8y8 commented Jul 13, 2017

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.

@graysonarts
Copy link
Contributor

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. task.object.id reads better to me than task.object_id.)

Does that make sense?

@williamlang
Copy link
Author

@RussTheAerialist @t8y8

is this what you're thinking?

Copy link
Collaborator

@t8y8 t8y8 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few comments for cleanup.

The question, do we want it to be target_type for the Target class or .type I think .type is fine since it's namespaced in the class.

def __repr__(self):
return "<Target#{id}, {target_type}>"

def get_type(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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):
        ...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.type

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@@ -0,0 +1,14 @@
"""Target class meant to abstract mappings to other objects"""
class Target():
def __init__(self, id, target_type):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name the function parameter id_ to avoid collision with the built in.

@@ -0,0 +1,14 @@
"""Target class meant to abstract mappings to other objects"""
class Target():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

self.target_type = target_type

def __repr__(self):
return "<Target#{id}, {target_type}>"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this line removed?

@williamlang
Copy link
Author

@RussTheAerialist added a test to prevent schedule_id getting deleted again :)

@t8y8 did the thing.

Copy link
Collaborator

@t8y8 t8y8 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

Two small nits

if datasource_element is not None:
datasource_id = datasource_element.get('id', None)
target = Target(datasource_id, "datasource")
#
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is technically never possible, right? (though a test for it is fine -- we may do this someday)

@t8y8
Copy link
Collaborator

t8y8 commented Jul 20, 2017

🚀🚀

Copy link
Contributor

@graysonarts graysonarts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 👨‍🎤

@t8y8 t8y8 merged commit 0d146fa into tableau:development Jul 20, 2017
@williamlang williamlang deleted the add-workbook-to-tasks branch July 24, 2017 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants