New Python SDK - How to convert TeamReponse/ProjectResponse objects into dataframe?

As the title suggests, how can I convert response objects from the new Python SDK into a pandas dataframe? Or can they be converted into dictionaries?

Using pd.DataFrame() on the objects seems to just put the whole object in a single column.

Thanks!

Managed to find a workaround!

list_of_dicts = [vars(obj) for obj in response]

2 Likes

Hi @anon25483135,

Glad you found a work around.

And yes, you can convert the responses from the new python client library into dictionaries using the class method to_dict().

NOTE: this only works at the top layer so if you do like api_response.data[0].to_dict() it will not work

Here’s an example of converting a response object to a python dict:

import asana
from asana.rest import ApiException
from pprint import pprint

# Configure OAuth2 access token for authorization: oauth2
configuration = asana.Configuration()
configuration.access_token = "<YOUR_ASANA_PERSONAL_ACCESS_TOKEN>"

# create an instance of the API class
task_api_instance = asana.TasksApi(asana.ApiClient(configuration))
project = '<PROJECT_GID>' # str | The project to filter tasks on. (optional)

try:
    # Get multiple tasks
    task_api_response_dict = task_api_instance.get_tasks(project=project).to_dict()
    # Access name of first task in api_response_dict
    pprint(task_api_response_dict['data'][0]['name'])
except ApiException as e:
    print("Exception when calling TasksApi->get_tasks: %s\n" % e)

WARNING: You might want to be careful in converting the response object into a dict because it will contain all the properties of a resource schema.

Scenario:

Let’s say you make a request to Get multiple tasks without specify any opt_fields → in our docs we say this returns an array of compact task schema in the 200 repsonse

EX:

api_response = task_api_instance.get_tasks(project=project)

What you might expect:

{'data': [{'gid': 'TASK_GID_1',
           'name': 'Task 1',
           'resource_subtype': 'default_task',
           'resource_type': 'task'},
          {'gid': '<TASK_GID_2>',
           'name': 'Task 2',
           'resource_subtype': 'default_task',
           'resource_type': 'task'},],
 'next_page': None}

Actual result:

{'data': [{'actual_time_minutes': None,
           'approval_status': None,
           'assignee': None,
           'assignee_section': None,
           'assignee_status': None,
           'completed': None,
           'completed_at': None,
           'completed_by': None,
           'created_at': None,
           'created_by': None,
           'custom_fields': None,
           'dependencies': None,
           'dependents': None,
           'due_at': None,
           'due_on': None,
           'external': None,
           'followers': None,
           'gid': 'TASK_GID_1',
           'hearted': None,
           'hearts': None,
           'html_notes': None,
           'is_rendered_as_separator': None,
           'liked': None,
           'likes': None,
           'memberships': None,
           'modified_at': None,
           'name': 'Task 1',
           'notes': None,
           'num_hearts': None,
           'num_likes': None,
           'num_subtasks': None,
           'parent': None,
           'permalink_url': None,
           'projects': None,
           'resource_subtype': 'default_task',
           'resource_type': 'task',
           'start_at': None,
           'start_on': None,
           'tags': None,
           'workspace': None},
          {'actual_time_minutes': None,
           'approval_status': None,
           'assignee': None,
           'assignee_section': None,
           'assignee_status': None,
           'completed': None,
           'completed_at': None,
           'completed_by': None,
           'created_at': None,
           'created_by': None,
           'custom_fields': None,
           'dependencies': None,
           'dependents': None,
           'due_at': None,
           'due_on': None,
           'external': None,
           'followers': None,
           'gid': '<TASK_GID_2>',
           'hearted': None,
           'hearts': None,
           'html_notes': None,
           'is_rendered_as_separator': None,
           'liked': None,
           'likes': None,
           'memberships': None,
           'modified_at': None,
           'name': 'Task 2',
           'notes': None,
           'num_hearts': None,
           'num_likes': None,
           'num_subtasks': None,
           'parent': None,
           'permalink_url': None,
           'projects': None,
           'resource_subtype': 'default_task',
           'resource_type': 'task',
           'start_at': None,
           'start_on': None,
           'tags': None,
           'workspace': None},],
 'next_page': None}

Notice how all the other properties are “None”

It might be safer to use the call_api option if you don’t want excess data form the model.

Here’s an example request:

import asana
from asana.rest import ApiException
from pprint import pprint

# Configure OAuth2 access token for authorization: 
configuration = asana.Configuration()
configuration.access_token = '<YOUR_ASANA_PERSONAL_ACCESS_TOKEN>'
api_client = asana.ApiClient(configuration)

# GET - get a task
api_response = api_client.call_api(
    "/tasks",
    "GET",
    path_params={},
    query_params=[('project', '<PROJECT_GID>')],
    header_params={"Accept": "application/json; charset=utf-8"},
    body=None,
    post_params=[],
    files={},
    response_type=object, # If there is an existing response model for the resource you can use that EX: "TaskResponseData" or you can specify one of the following types: float, bool, bytes, str, object
    auth_settings=["oauth2"],
    async_req=None,
    _return_http_data_only=True,
    _preload_content=True,
    _request_timeout=None,
    collection_formats={},
)
pprint(api_response)

Here’s what the response would look like:

{'data': [{'gid': '<TASK_GID_1>',
           'name': 'Task 1',
           'resource_subtype': 'default_task',
           'resource_type': 'task'},
          {'gid': '<TASK_GID_2>',
           'name': 'Task 2',
           'resource_subtype': 'default_task',
           'resource_type': 'task'}]}
2 Likes

Thanks for the detailed response @John_Vu I will give that a go! Noted about the excess columns as well - I was wondering about that.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.