Skip to content

Example: Task Dependencies

kporangehat edited this page Dec 21, 2010 · 6 revisions

Task dependencies work very simply in the API and there are only a couple of things to keep in mind when interacting with them.

Create Tasks

Let's create a couple of Tasks and create dependencies between them. First we'll create a 'Layout' Task for our Shot:

    data = {
        'project': {'type':'Project', 'id':65},
        'content': 'Layout',
        'start_date': '2010-04-28',
        'due_date': '2010-05-05',
        'entity': {'type':'Shot', 'id':860}
        }    
    result = sg.create(Task, data)

Returns:

{'content': 'Layout',
 'due_date': '2010-05-05',
 'entity': {'id': 860, 'name': 'bunny_010_0010', 'type': 'Shot'},
 'id': 556,
 'project': {'id': 65, 'name': 'Demo Animation Project', 'type': 'Project'},
 'start_date': '2010-04-28',
 'type': 'Task'}

Now let's create an 'Anm' Task for our Shot:

    data = {
        'project': {'type':'Project', 'id':65},
        'content': 'Anm',
        'start_date': '2010-05-06',
        'due_date': '2010-05-12',
        'entity': {'type':'Shot', 'id':860}
        }    
    result = sg.create(Task, data)

Returns:

{'content': 'Anm',
 'due_date': '2010-05-12',
 'entity': {'id': 860, 'name': 'bunny_010_0010', 'type': 'Shot'},
 'id': 557,
 'project': {'id': 65, 'name': 'Demo Animation Project', 'type': 'Project'},
 'start_date': '2010-05-06,
 'type': 'Task'}

Create A Dependency

Tasks each have an upstream_tasks field and a downstream_tasks field. Each field is a list [] type and can contain zero, one, or multiple Task entity hashes representing the dependent Tasks. Here is how to create a dependency between our 'Layout' and 'Anim' Tasks:

    # make 'Layout' and upstream Task to 'Anm'. (aka, make 'Anm' dependent on 'Layout')
    result = sg.update('Task', 557, {'upstream_tasks':[{'type':'Task','id':556}])

Returns:

[{'id': 557,
  'type': 'Task',
  'upstream_tasks': [{'id': 556, 'name': 'Layout', 'type': 'Task'}]}]

This will also automatically update the downstream_tasks field on 'Layout' to include the 'Anm' Task.

Query Tasks with Dependency Fields

So now lets look at the Tasks we've created and their dependency-related fields:

    filters = [
        ['entity', 'is', {'type':'Shot', 'id':860}]
    ]
    fields = [
        'content',
        'start_date',
        'due_date',
        'upstream_tasks',
        'downstream_tasks',
        'dependency_violation', 
        'pinned'
        ]
    result = sg.find("Task", filters, fields)

Returns:

[{'content': 'Layout',
  'dependency_violation': False,
  'downstream_tasks': [{'type': 'Task', 'name': 'Anm', 'id': 557}],
  'due_date': '2010-05-05',
  'id': 556,
  'pinned': False,
  'start_date': '2010-04-28',
  'type': 'Task',
  'upstream_tasks': []},
 {'content': 'Anm',
  'dependency_violation': False,
  'downstream_tasks': [{'type': 'Task', 'name': 'FX', 'id': 558}],
  'due_date': '2010-05-12',
  'id': 557,
  'pinned': False,
  'start_date': '2010-05-06',
  'type': 'Task',
  'upstream_tasks': [{'type': 'Task', 'name': 'Layout', 'id': 556}]}, 
...    

(Note that we have also created additional Tasks for this Shot but we're going to focus on these first two for simplicity)

Updating the End Date on a Task will update dependent Task dates

If we update the due_date field on our Layout Task, we'll see that the 'Anm' Task dates will automatically get pushed back to keep the dependency satisfied.

    result = sg.update('Task', 556, {'due_date': '2010-05-07'})

Returns:

[{'due_date': '2010-05-07', 'type': 'Task', 'id': 556}]

Our Tasks now look like this (notice the new dates on the 'Anm' Task):

[{'content': 'Layout',
  'dependency_violation': False,
  'downstream_tasks': [{'type': 'Task', 'name': 'Anm', 'id': 557}],
  'due_date': '2010-05-07',
  'id': 556,
  'pinned': False,
  'start_date': '2010-04-28',
  'type': 'Task',
  'upstream_tasks': []},
 {'content': 'Anm',
  'dependency_violation': False,
  'downstream_tasks': [{'type': 'Task', 'name': 'FX', 'id': 558}],
  'due_date': '2010-05-14',
  'id': 557,
  'pinned': False,
  'start_date': '2010-05-10',
  'type': 'Task',
  'upstream_tasks': [{'type': 'Task', 'name': 'Layout', 'id': 556}]}, 
...  

Creating a Dependency Violation by pushing up a Start Date

Task Dependencies can work nicely if you are pushing out an end date for a Task as it will just recalculate the dates for all of the dependent Tasks. But what if we push up the Start Date of our 'Anm' Task to start before our 'Layout' Task is scheduled to end?

    result = sg.update('Task', 557, {'start_date': '2010-05-06'})

Returns:

[{'type': 'Task', 'start_date': '2010-05-06', 'id': 557}]

Our Tasks now look like this:

[{'content': 'Layout',
  'dependency_violation': False,
  'downstream_tasks': [{'type': 'Task', 'name': 'Anm', 'id': 557}],
  'due_date': '2010-05-07',
  'id': 556,
  'pinned': False,
  'start_date': '2010-04-28',
  'type': 'Task',
  'upstream_tasks': []},
 {'content': 'Anm',
  'dependency_violation': True,
  'downstream_tasks': [{'type': 'Task', 'name': 'FX', 'id': 558}],
  'due_date': '2010-05-12',
  'id': 557,
  'pinned': True,
  'start_date': '2010-05-06',
  'type': 'Task',
  'upstream_tasks': [{'type': 'Task', 'name': 'Layout', 'id': 556}]},
 ...  

Because the 'Anm' Task start_date depends on the due_date of the 'Layout' Task, this change creates a dependency violation. The update succeeds, but Shotgun has also set the dependency_violation field to True and has also updated the pinned field to True.