TypeError: 'TaskResponseArray' object is not iterable

Hi there! I’m updating my API calls in Python to meet the requirements for v4. I’m by no means an expert in Python so I’m not sure how to deal with this.

My code:

configuration = asana.Configuration()
configuration.access_token = '<PAT>'
project_id = "<redacted>"

tasks_call = asana.TasksApi(asana.ApiClient(configuration))
tasks_call_opts = ["name","assignee.name","completed","memberships.section.name"]
tasks_data = tasks_call.get_tasks_for_project(project_id, opt_fields=tasks_call_opts)

...

for c, x in enumerate(tasks_data):
   #some actions

When I run this, it returns TypeError: 'TaskResponseArray' object is not iterable. This worked in v3, so I’m not sure what changed with the API response. Thanks!

Hi @foks

I am assuming the Python Interpreter is spitting out the are error is on the below line

But could you please confirm the same, before I start digging into it more.

1 Like

Hi @foks,

TLDR; to make the iteration work call tasks_data.data.

The v4 version of the python client libraries does not auto abstract the data property from the response. This can be confusing since the class name of the response is asana.models.task_response_array.TaskResponseArray. The reason for not abstracting the data wrapper is because data and next_page live at the same level so in scenarios where there is a next page if we return the content of data developers wound’t be able to access .next_page from the response i.e.,:

{
    "data": {
        ...
    },
    "next_page": {
        ...
    }
}

NOTE: next_page is only present in the response when a limit is provided in the query params or the request or when there is a lot of data to be returned.

Of course we could reconsider this design depending on developer feedback. However, for now I believe all of the responses from the v4 python client libraries have the response data wrapped in a data wrapper so you must call .data in order to access the data inside of that wrapper. This is consistent with our docs:

Here’s what your update script would look like:

configuration = asana.Configuration()
configuration.access_token = '<PAT>'
project_id = "<redacted>"

tasks_call = asana.TasksApi(asana.ApiClient(configuration))
tasks_call_opts = ["name","assignee.name","completed","memberships.section.name"]
tasks_data = tasks_call.get_tasks_for_project(project_id, opt_fields=tasks_call_opts)

...

for c, x in enumerate(tasks_data.data):
   #some actions

If you are curious, our new libraries are auto generated from a code generator (swagger codegen) using our SDK OpenAPI Spec. Here is the location of the spec where TaskResponseArray is being defined. TaskResponseArray is the name of the schema that Get tasks from a project endpoint references in our OpenAPI Spec.

2 Likes

This is a great response! Thank you so much for the clarification. Makes total sense.

The issue for me now is that the data is no longer “subscriptable”. e.g. this from another section of code added after I wrote this initial post. Here, I’m looking to pull status updates and get the title of the most-recent one:

configuration = asana.Configuration()
configuration.access_token = '<PAT>'
project_id = "<redacted>"

updates_call = asana.StatusUpdatesApi(asana.ApiClient(configuration))
updates_call_opts = ["status_type","text","title"]
updates_data = updates_call.get_statuses_for_object(project_id, opt_fields=updates_call_opts)
updates_data = updates_data.data

for c, x in enumerate(updates_data):
    if c == 0:
        update_text = x["text"]
        update_title = x["title"]
exit()

The error now is

Traceback (most recent call last):
  File "script.py", line 63, in <module>
    update_text = x["text"]
TypeError: 'StatusUpdateResponse' object is not subscriptable

(I can use a more similar example if necessary but I think the issue would be the same.)

Hi @foks,

The responses in the v4 python client libraries return an object of that resource . In this scenario the response object is <class 'asana.models.status_update_response_array.StatusUpdateResponseArray'>. In order to access properties of this response you can use the dot notation so for example using your example:

configuration = asana.Configuration()
configuration.access_token = '<PAT>'
project_id = "<redacted>"

updates_call = asana.StatusUpdatesApi(asana.ApiClient(configuration))
updates_call_opts = ["status_type","text","title"]
updates_data = updates_call.get_statuses_for_object(project_id, opt_fields=updates_call_opts) # -> StatusUpdateResponseArray
updates_data = updates_data.data # -> list of StatusUpdateResponse

for c, x in enumerate(updates_data):
    if c == 0:
        update_text = x.text
        update_title = x.title
exit()

If you would like to use bracket notation you would need to first convert the response into a dict:

configuration = asana.Configuration()
configuration.access_token = '<PAT>'
project_id = "<redacted>"

updates_call = asana.StatusUpdatesApi(asana.ApiClient(configuration))
updates_call_opts = ["status_type","text","title"]
updates_data = updates_call.get_statuses_for_object(project_id, opt_fields=updates_call_opts)
updates_data_dict = updates_data.to_dict() # -> dict

for c, x in enumerate(updates_data_dict["data"]):
    if c == 0:
        update_text = x["text"]
        update_title = x["title"]
exit()

TIP: Check out the docs in the python-asana README.md (Doc for: get_statuses_for_object) for more details of the object that is returned.

2 Likes

Aha! Thanks so much for the additional response. The dot notation works great!

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