xdevplatform/twitter-python-ads-sdk

7.0.2 Type Error in Oauth Request

Closed this issue ยท 12 comments

Ever since 2020-10-08 we have been receiving the following error when trying to make a LineItem.async_stats_job_result call.

File "D:\python\lib\site-packages\twitter_ads\http.py", line 105, in __oauth_request
url = self.__domain() + self._resource
TypeError: can only concatenate str (not "bytes") to str

Hey @chris-smith-publicis can you provide steps to reproduce the issue?

Hi. I ran into the exact same issue with async. I just tested sync and it works fine. Here is the code I am running(It is from your analytics example.) Python 3.7.4 Please let me know if there's any other information I can provide to help you reproduce the issue.

from twitter_ads.client import Client
from twitter_ads.campaign import Campaign
from twitter_ads.enum import GRANULARITY,METRIC_GROUP,PLACEMENT
from twitter_ads.campaign import LineItem
from twitter_ads.utils import split_list
from twitter_ads.creative import AccountMedia
import time

CONSUMER_KEY = 'CONSUMER_KEY'
CONSUMER_SECRET = 'CONSUMER_SECRET'
ACCESS_TOKEN = 'ACCESS_TOKEN'
ACCESS_TOKEN_SECRET = 'ACCESS_TOKEN_SECRET'
ACCOUNT_ID = "ACCOUNT_ID"

client = Client(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
account = client.accounts(ACCOUNT_ID)

queued_job_ids = []
for chunk_ids in split_list(ids, 20):
queued_job_ids.append(LineItem.queue_async_stats_job(account, chunk_ids, metric_groups).id)

print(queued_job_ids)

seconds = 30
time.sleep(seconds)

async_stats_job_results = LineItem.async_stats_job_result(account, job_ids=queued_job_ids)

async_data = []
for result in async_stats_job_results:
async_data.append(LineItem.async_stats_job_data(account, url=result.url))

print(async_data)

TypeError Traceback (most recent call last)
in
14 async_data = []
15 for result in async_stats_job_results:
---> 16 async_data.append(LineItem.async_stats_job_data(account, url=result.url))
17
18 print(async_data)

~\Anaconda3\lib\site-packages\twitter_ads\analytics.py in async_stats_job_data(klass, account, url, **kwargs)
114
115 response = Request(account.client, 'get', resource.path, domain=domain,
--> 116 raw_body=True, stream=True).perform()
117
118 return response.body

~\Anaconda3\lib\site-packages\twitter_ads\http.py in perform(self)
66 if self.client.trace:
67 self.__enable_logging()
---> 68 response = self.__oauth_request()
69 if response.code > 399:
70 raise Error.from_response(response)

~\Anaconda3\lib\site-packages\twitter_ads\http.py in __oauth_request(self)
103 resource_owner_secret=self._client.access_token_secret)
104
--> 105 url = self.__domain() + self._resource
106 method = getattr(consumer, self._method)
107

TypeError: can only concatenate str (not "bytes") to str

Any one find a solution to this? I'm seeing the same issues with async requests

Hey @chris-smith-publicis can you provide steps to reproduce the issue?

FrankOnBeach provided a similar example

I'm seeing the same error.

@tushdante has Anybody been able to find a solution to this issue? It looks like it might be within the SDK itself. As I've been cronning the async job every hour and seems to break in the afternoon before working later in the day

@tushdante has Anybody been able to find a solution to this issue? It looks like it might be within the SDK itself. As I've been cronning the async job every hour and seems to break in the afternoon before working later in the day

It is definitely in the SDK itself because it is a response that the oauth handler is recieiving is not in a format it expects

Hey all, so it turns out that the issue isn't originating from the SDK. We're seeing intermittent downtime with the async analytics endpoints causing the result.url field on the API response to being set to null, here:

for result in async_stats_job_results:
    async_data.append(LineItem.async_stats_job_data(account, url=result.url))

One workaround would be to increase the seconds in time.sleep(seconds) to something larger to allow for more processing time prior to fetching the results, or adding a check to ensure the results are available.

On the SDK side of things, it sounds like we'd want to add functionality to handle these types of cases (where an API endpoint is unavailable) but given current constraints this won't be addressed in the short term. That being said, our PRs are open and we're more than happy to assist in case someone from this thread wants to contribute.

Thanks @tushdante! I'm curious how much time your team would add to the time sleep. I've added around 90 seconds to delay the response and still seeing the oauth error. Would you be able to provide an example of how the second workaround would work?

@seanpdwyer7 I went a little extreme and threw a sleep(random.randint(120,240)) in there... it is most likely over kill but I did get a return set

@seanpdwyer7 one potential approach could be to modify twitter_ads/analytics.py to poll the GET stats endpoint and check to check for status: "SUCCESS prior to fetching the URL/results (in L#105). There would be a need to add some retry logic there, in case the status is PROCESSING. Definitely open to discussions/ideas if there's a better alternative.

So, as it turns out we do have rate-limiting and retry options available that should be able to help here.

Closing out this issue, resolution here