error using python library to search tasks

Hi,
The python Asana library is behaving weirdly. I am stepping through tasks a few days at a time so that I can do some historical reporting. This code will work for a few years then starts failing.

Issues

  1. How do i fix the error “asana.error.InvalidRequestError: Invalid Request: completed_on.after: Should be before completed_on.before” (details below)

  2. How do i add “new_goal_memberships” to your “Asana-Enable” or “Asana-Disable” header? I see nothing in the python library documentation to help

  3. what is the syntax to get 100 (or more?) results at one time? i could not get limit to change getting max 50 results.

System Details: Python 3.11, Windows 11, Premium Asana

Code

    # start_date and end_date are both date variables.
    time.sleep(1.5) # Search can only be called 50 per minute
    task_results = client.tasks.search_tasks_for_workspace(WORKSPACE_GID, 
                {
                'completed_on.after':start_date,
                'text': 'visit', 
                'sort_by': 'completed_at', 
                'sort_ascending': 'true',
                'completed_on.before':end_date,
                }, 
                opt_pretty=True)

Output

daterange:2021-01-02 to 2021-01-07
storing: items num/overall:( 6/49)
daterange:2021-01-08 to 2021-01-13
storing: items num/overall:( 3/52)
daterange:2021-01-14 to 2021-01-19
storing: items num/overall:( 3/55)
daterange:2021-01-20 to 2021-01-25
storing: items num/overall:( 5/60)
daterange:2021-01-26 to 2021-01-31
Traceback (most recent call last):
File “c:\Users\donal\OneDrive\Documents\python dev\asana stats\get_asana.py”, line 94, in
find_tasks(start_date, end_date)
File “c:\Users\donal\OneDrive\Documents\python dev\asana stats\get_asana.py”, line 30, in find_tasks
store_results(task_results)
File “c:\Users\donal\OneDrive\Documents\python dev\asana stats\get_asana.py”, line 40, in store_results
for index, element in enumerate(task_results):
File “C:\Program Files\Python311\Lib\site-packages\asana\page_iterator.py”, line 58, in items
for page in self:
File “C:\Program Files\Python311\Lib\site-packages\asana\page_iterator.py”, line 40, in next
result = self.get_initial()
^^^^^^^^^^^^^^^^^^
File “C:\Program Files\Python311\Lib\site-packages\asana\page_iterator.py”, line 69, in get_initial
return self.client.get(self.path, self.query, **self.options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “C:\Program Files\Python311\Lib\site-packages\asana\client.py”, line 174, in get
return self.request(‘get’, path, params=query, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “C:\Program Files\Python311\Lib\site-packages\asana\client.py”, line 92, in request
raise STATUS_MAPresponse.status_code
asana.error.InvalidRequestError: Invalid Request: completed_on.after: Should be before completed_on.before

Hi,

Can we see exactly the date you are passing for before and after params?

Looks like this in Javascript, if that helps.

asana.Client.create({
            defaultHeaders: {
                'Asana-Enable': 'new_user_task_lists',
                'Asana-Disable': 'new_project_templates'
            })

That’s expected, when running a search you have to play with the creation date of the tasks to be able to request the next batch. See Search tasks in a workspace

dates as string look like:
start:2018-02-01 end:2018-02-06
start:2018-02-07 end:2018-02-12

When the query works, the dates are working with the right range.

The higher level function that loops through dates is:

start_date = datetime.date.fromisoformat(OVERALL_START_DATE)
next_year = start_date.replace(year=start_date.year + 1)
while start_date < datetime.date.today():
end_date = start_date + datetime.timedelta(days=NUM_DAYS_PER_QUERY)
if end_date >= next_year:
end_date = next_year - datetime.timedelta(days=1)
next_year = next_year.replace(year=next_year.year + 1)

find_tasks(start_date, end_date)

start_date = end_date + datetime.timedelta(days=1)

Here are the dates up to and including an error:

start:2021-01-20 end:2021-01-25
storing items num/overall:( 3/55)
daterange:2021-01-20 to 2021-01-25
start:2021-01-26 end:2021-01-31
storing items num/overall:( 5/60)
daterange:2021-01-26 to 2021-01-31
start:2021-02-01 end:2021-01-31
Traceback (most recent call last):
File “c:\Users\donal\OneDrive\Documents\python dev\asana stats\get_asana.py”, line 95, in
find_tasks(start_date, end_date)
File “c:\Users\donal\OneDrive\Documents\python dev\asana stats\get_asana.py”, line 31, in find_tasks
store_results(task_results)
File “c:\Users\donal\OneDrive\Documents\python dev\asana stats\get_asana.py”, line 41, in store_results
for index, element in enumerate(task_results):
File “C:\Program Files\Python311\Lib\site-packages\asana\page_iterator.py”, line 58, in items
for page in self:
File “C:\Program Files\Python311\Lib\site-packages\asana\page_iterator.py”, line 40, in next
result = self.get_initial()
^^^^^^^^^^^^^^^^^^
File “C:\Program Files\Python311\Lib\site-packages\asana\page_iterator.py”, line 69, in get_initial
return self.client.get(self.path, self.query, **self.options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “C:\Program Files\Python311\Lib\site-packages\asana\client.py”, line 174, in get
return self.request(‘get’, path, params=query, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “C:\Program Files\Python311\Lib\site-packages\asana\client.py”, line 92, in request
raise STATUS_MAPresponse.status_code
asana.error.InvalidRequestError: Invalid Request: completed_on.after: Should be before completed_on.before

ah i found the answer to #1. a bug in my date generations has them generated backwards sometimes.

Anyone have answer to #2 and #3 ?
The syntax given above to add headers is not correct for python and i can’t find the right client function.

#3 - the limit is stated as 100, but i can only get 50 at a time

How do you create your python client? did you look at the python library source code.

To me, it doesn’t really matter, you have to loop through pages anyway even if they were 100 items long don’ t you?

i thought i could find the answer without reading source code from the library.
After looking at the source code, i still don’t know how to change headers. Care to point in the right direction.
My python asana code is:

client = asana.Client.access_token(PERSONAL_ACCESS_TOKEN)

task_results = client.tasks.search_tasks_for_workspace(WORKSPACE_GID,
{
‘completed_on.after’:start_date,
‘text’: ‘visit’,
‘completed_on.before’:end_date,
},
opt_pretty=True)

result = client.tasks.get_task(task_gid)

  1. limit of 50 means the program makes twice the calls and takes twice as long to run. Getting data for 4 days at a time for 5 years means close to 10 minutes runtime. (as the search task can only run 50 times/minute, even on paid platform).

Doubling that limit to 100 would halve the number of calls and halve the time.

I am surprised you don’t have a create step like me asana.Client.create(...)

I don’t see in your code passing a value for limit

  1. I followed the code examples and they did not have asana.client.create step

  2. whatever syntax i tried for limit made no changes so i removed it. What is the correct syntax?

task_results = client.tasks.search_tasks_for_workspace(WORKSPACE_GID,
{
‘completed_on.after’:start_date,
‘text’: ‘visit’,
‘completed_on.before’:end_date,
},
opt_pretty=True, limit=100)
or
task_results = client.tasks.search_tasks_for_workspace(WORKSPACE_GID,
{
‘completed_on.after’:start_date,
‘text’: ‘visit’,
‘completed_on.before’:end_date,
‘limit’:‘100’
},
opt_pretty=True)
or something else?

The GitHub gives you the syntax: GitHub - Asana/python-asana: Official Python client library for the Asana API v1

Maybe you are not using the latest version because I don’t see the method you used but a different one…

Thanks for providing the github link with better documentation than on Asana website. It would be helpful if the Asana documentation pointed here.

I installed with “pip install asana”. The version installed is 3.2.1 – the same version as on github.

the function i call is in tasks.py, line 351:

def search_tasks_for_workspace(self, workspace_gid, params=None, **options):

PS - my tasks.py does not have search_in_workspace function

So you got the latest lib but it doesn’t have the function we see on GitHub? :thinking:
Anyway, the limit is definitely part of the search parameters… I always assumed it worked but maybe all this time I was not getting 100 results :person_shrugging:

Hmm is right. I used python pip to install. i don’t know how to tell where pip sourced the files.

Strange to have 2 versions.

For limit, i tried the other way and limited to 5 results for testing. It always returned more. The git docs refer to using item_limit:# so i will try that later. Note the Asana doc refers to the parameter as limit as per my above code

I always refer back to the source code in cases like these because the doc might not be aligned with the releases…

Hello,

To address the error “asana.error.InvalidRequestError: Invalid Request: completed_on.after: Should be before completed_on.before,” it seems there’s an issue with the date range you’re passing. Ensure that the “after” date is indeed before the “before” date. Double-check the date values being used in your request.

Regarding adding “new_goal_memberships” to the header in Python, you can use the client.headers attribute to modify the default headers. Here’s an example:

python code

import asana

client = asana.Client.access_token(‘your_access_token’)
client.headers.update({‘Asana-Enable’: ‘new_goal_memberships’})

For fetching more than 50 results at a time, you can use pagination. Unfortunately, the Asana API limits each request to 50 items, but you can iterate through the results using the “offset” parameter to get the next set of results.

Here’s an example using the Python library:

python code

import asana

client = asana.Client.access_token('your_access_token')

# Set the initial offset
offset = 0

# Fetch the first 50 tasks
results = client.tasks.find_by_project('your_project_id', limit=50, offset=offset)

# Process the results
for task in results:
    # Do something with each task

# Update the offset to fetch the next set of results
offset += 50

# Fetch the next 50 tasks
next_results = client.tasks.find_by_project('your_project_id', limit=50, offset=offset)

# Continue processing the results...

This way, you can manually paginate through the results and fetch more than 50 tasks.
Below are the links to the finest learning platforms

  1. Iqra Technology
  2. JavaPoint

Actually the limit is 100:

It looks like @khanzain4593 is using our <v3.X.X python client library. In these versions of the library the pagination feature was implemented with a default limit of 50 (perhaps because back then Asana had an API limit of 50 but now it has been increased to 100)

  1. This is where the default limit is being defined in the v3.2.2 python client library (Note that it is called page_size)
  2. This is where it is being consumed → Notice that the limit query param uses this page_size value.

You can change this default limit by overwriting the default page_size of 50 from the client (See: README.md docs for <v3.X.X)

When making a request with an endpoint that returns an array of values, the python library will return a generator object. If you try to loop through this object it will give you back one item at a time so the 50 shouldn’t matter much in terms of consumption.

The one thing that it does affect is how the request is being made behind the scene. You will probably run into API rate limits sooner since the library is making a request for 50 items at a time vs 100. So let’s say you have a project with 1000 tasks and you make a request to Get multiple tasks endpoint. By default the library will make 1000/50 = 20 API requests to get all 1000 tasks vs if the default was set to 100 it would take 1000/100 = 10 API requests.

In python-asana v5.X.X we set the default to 100 as seen here → here is an example of where that is being referenced: get_tasks

1 Like