Description
For googleads-python-lib/examples/adwords/v201502/advanced_operations/find_and_remove_criteria_from_shared_set.py
The code provided currently breaks if it encounters a negative shared set of keywords that is empty, with no keywords or placements.
This may or may not be a deliberate design decision to crash the program if it encounters a shared set that has no keywords or placements.
But for people who are using this code for more than just finding and removing criteria and/or people who wouldn't like their code to stop as soon as it encounters an empty shared sets, I have some fixes/workarounds for this behavior (that don't involve try).
There are two reasons that this code throws errors and breaks when it encounters an empty shared set. For each of the reasons, I have provided, solutions and/or workarounds to these problems, the probable cause of the program-stopping errors, as well as the error output.
Exhibit A:
Problem:
When the code sets the initial values to look for criteria (line108), it sets totalNumEntries to be 1 in page. This gets it into get into the loop looking at the result of page = shared_criterion_service.get(selector) (line 111) and then tries to look at page['entries'], where it then crashes, because page doesn't have 'entries' because the shared set it is looking at has no entries.
error:
Printed below is the page(with a print page statement) for an empty shared set and the error that the code throws:
(SharedCriterionPage){
totalNumEntries = 0
Page.Type = "SharedCriterionPage"
}
Traceback (most recent call last):
File "test6_add_gen_neg_keywords.py", line 423, in
newly_visited_shared_sets = main(adwords_client, campaign[0], visited_shared_sets, shared_set_table)
File "test6_add_gen_neg_keywords.py", line 164, in main
if page['entries']:
File "/opt/devel/lib/python2.7/site-packages/suds/sudsobject.py", line 154, in getitem
return getattr(self, name)
AttributeError: 'SharedCriterionPage' object has no attribute 'entries'
Solution:
One solution (that I've implemented) is to check that the totalNumEntries is still more than 0 before trying to access page['entries'] in the line if page['entries']:
if page['totalNumEntries'] > offset:
if page['entries']:
Another potential solution that I haven't tested is, instead of writing
if page['entries']:
at line 112 instead write
if 'entries' in page:
as written in line 79 of this code, since that page query doesn't break if a campaign doesn't have shared sets so this syntax seems to work.
Exhibit B:
Problem:
The code breaks at response = shared_criterion_service.mutate(operations) (line 145)
if the operations doesn't have any criterion_ids to work on, aka if criterion_ids is an empty list. I don't know why asking it to remove nothing breaks it, but I do have a solution.
Error:
Printed below is the page for an empty shared set and the error given when trying to run this program
(SharedCriterionPage){
totalNumEntries = 0
Page.Type = "SharedCriterionPage"
}
2015-06-23 13:40:08 suds.client ERROR <suds.sax.document.Document instance at 0x1232ab8>
Traceback (most recent call last):
File "test6_add_gen_neg_keywords.py", line 423, in
newly_visited_shared_sets = main(adwords_client, campaign[0], visited_shared_sets, shared_set_table)
File "test6_add_gen_neg_keywords.py", line 205, in main
response = shared_criterion_service.mutate(operations)
File "/opt/devel/lib/python2.7/site-packages/googleads/common.py", line 296, in MakeSoapRequest
for arg in args])
File "/opt/devel/lib/python2.7/site-packages/suds/client.py", line 521, in call
return client.invoke(args, kwargs)
File "/opt/devel/lib/python2.7/site-packages/suds/client.py", line 581, in invoke
result = self.send(soapenv)
File "/opt/devel/lib/python2.7/site-packages/suds/client.py", line 619, in send
description=tostr(e), original_soapenv=original_soapenv)
File "/opt/devel/lib/python2.7/site-packages/suds/client.py", line 670, in process_reply
raise WebFault(fault, replyroot)
suds.WebFault: Server raised fault: '[NotEmptyError.EMPTY_LIST @ operations]'
Solution:
You do not need to do the remove operation, or request a response for it if there are no criterion_ids to remove
Therefore, I placed the block of code responsible for removing criterion and reporting on it in an if clause in order to check if there are any criterion_ids to remove before trying to remove any criteria
if criterion_ids:
block of code for removing and reporting on criterions (lines134-151)
I hoped that helped you!