Bingads SDK Python Suds sending wrong envelope - python

Using BingAds SDK for Python I am not able to perform any operation to update because of a bug that I cannot resolve.
The SDK uses Suds for the handling of SOAP operation.
Here is the wsdl:
https://campaign.api.bingads.microsoft.com/Api/Advertiser/CampaignManagement/v13/CampaignManagementService.svc?singleWsdl
# This function internally configures the authorization for BingAdsAPI
campaign_service = bc.get_bing_ads_client(account=account, service='CampaignManagementService')
update_ad_groups_request = campaign_service.factory.create('UpdateAdGroupsRequest')
update_ad_groups_request.CampaignId = campaign_id
ad_group = campaign_service.factory.create('AdGroup')
ad_group.Id = ad_group_id
bid = campaign_service.factory.create('Bid')
bid.Amount = new_bid
ad_group.CpcBid = bid
update_ad_groups_request.AdGroups = campaign_service.factory.create('ArrayOfAdGroup')
update_ad_groups_request.AdGroups.AdGroup.append(ad_group)
campaign_service.UpdateAdGroups(update_ad_groups_request)
When I send it it fails saying:
suds.WebFault: Server raised fault: 'The formatter threw an exception
while trying to deserialize the message: There was an error while
trying to deserialize parameter
https://bingads.microsoft.com/CampaignManagement/v13:CampaignId. The
InnerException message was 'There was an error deserializing the
object of type System.Int64. The value '' cannot be parsed as the type
'Int64'.'. Please see InnerException for more details.'
When I open the soap Envelope:
....</SOAP-ENV:Header><ns1:Body><ns0:UpdateAdGroupsRequest><ns0:CampaignId>
<ns0:CampaignId>377072652</ns0:CampaignId><ns0:AdGroups><ns0:AdGroup><ns0:CpcBid>
<ns0:Amount>0.91</ns0:Amount></ns0:CpcBid><ns0:Id>1256742239729725</ns0:Id>
<ns0:Network/><ns0:PrivacyStatus/><ns0:Status/></ns0:AdGroup></ns0:AdGroups>
</ns0:CampaignId></ns0:UpdateAdGroupsRequest></ns1:Body></SOAP-ENV:Envelope>
Note how the Campaign ID is twice and also it wraps the whole envelope. I tried also directly with Suds and I have the same issue, other functions also have the same issue.
Because moving to parsing the envelopes by myself, I was wondering if someone has had this issue and what could be the reason.

You should not need to explicitly create a 'Request' object i.e., via the SUDS service client you can pass the request parameters directly via the UpdateAdGroups operation. To confirm I started with expanded_text_ads.py and inserted the following snippet immediately after the AddAdGroups example.
ad_groups=campaign_service.factory.create('ArrayOfAdGroup')
ad_group=set_elements_to_none(campaign_service.factory.create('AdGroup'))
ad_group.Id=ad_group_ids['long'][0]
cpc_bid=campaign_service.factory.create('Bid')
cpc_bid.Amount=0.11
ad_group.CpcBid=cpc_bid
ad_groups.AdGroup.append(ad_group)
output_status_message("-----\nUpdateAdGroups:")
add_ad_groups_response=campaign_service.UpdateAdGroups(
CampaignId=campaign_ids['long'][0],
AdGroups=ad_groups
)
output_status_message("PartialErrors:")
output_array_of_batcherror(add_ad_groups_response.PartialErrors)
I hope this helps! Please let me know if you have any follow up questions.

Related

Understand the serverVerificationData in_app_purchase Flutter

I have done all the setup to verify my receipts server side (in python with the requests package).
Here is my code :
url = "https://buy.itunes.apple.com/verifyReceipt"
request_body = {"receipt-data": token}
headers = {'Content-Type': 'application/json'}
response = requests.post(url=url, headers=headers, data=request_body)
The only variable here is token that is sent from the client (flutter) and that is : purchaseDetails.verificationData.serverVerificationData.
I can't verify the receipt because if i pass token as string, i receive always a 21002 error (malformed).
If i try something like this in python :
token = base64.b64encode(token)
It throws this error : a bytes-like object is required, not 'str' which i don't understand because i am actually passing a bytes object.
What is the correct format to pass to the POST request to verify the iOS receipt ?
Is the flutter one correct or should we encode something ?
Any concrete example will be accepted because i could not find any.
PS : i am redirected to the sandbox url "https://sandbox.itunes.apple.com/verifyReceipt" if the production one fails. The sandbox response is the same as the production one (statusCode: 21002)
It looks like either your receipt is not correct ( sandbox has issues sometimes ) or your server-side setup is wrong
For the first point, you can try creating a receipt by generating a storeKit config file.
This can't be done in flutter, you have to open iOS module with code and setup storekit config file by going here.
After setting up the storekit file, you can either run the app from xCode directly or just close xCode and run from your preferred flutter IDE
Now, iOS will never hit the production purchase identifiers when you try to fetch/buy products from the app, and instead fetch the products from your storekit config and generate a receipt from those. This receipt is accepted by apple sandbox verification endpoint, you can also test refunds and subscription cancellations from xCode using a storekit config.
For the second point, you have to enable the app specific shared secret in iTunes connect and then use that in the 'password' key in the receipt validation API.
Here is where you find it
AppStoreConnect > Your app > Subscriptions
If it still doesn't solve the issue, I'd be happy to assist further.
EDIT: I just tested purchasing an auto renewable subscription purchased in sandbox (not storeki
t) and then validating it using the sandbox URL and it returned the correct receipt data. In your post above, you don't need to base64 encode the purchaseDetails.verificationData.serverVerificationData since its already encoded. Have you tested this on postman? It Works there
EDIT: so the request is malformed because you are not sending data as String so you need to dump the dict :
request_body = json.dumps({"receipt-data": token})

TypeError: Consumer key must be string or bytes, not NoneType when authentication

Planning to use variables to authorize tweepy with Twitter's API, but it shows the following:
TypeError: Consumer key must be string or bytes, not NoneType when authentication
Code below:
import tweepy
import os
consumera = os.environ.get('TWICK')
consumerb = os.environ.get('TWICS')
accessa = os.environ.get('TWIAT')
accessb = os.environ.get('TWIATS')
auth = tweepy.OAuthHandler(consumera, consumerb)
auth.set_access_token(accessa, accessb)
api = tweepy.API(auth)
status = api.update_status(status="Test tweet.")
I've tried using other authentication methods, such as:
consumera = os.environ.get('TWICK')
consumerb = os.environ.get('TWICS')
accessa = os.environ.get('TWIAT')
accessb = os.environ.get('TWIATS')
client = tweepy.Client(consumer_key=consumera,
consumer_secret=consumerb,
access_token=accessa,
access_token_secret=accessb
)
Any fix?
Additional info: I was planning to run it through GitHub actions but without exposing the keys in the source code - and I put all the keys as secrets, so it requires environmental access. Tested on Ubuntu (both local and under GitHub Actions), but no luck.
Perhaps a typo problem? NoneType is caused because one of the methods is receiving None, which is returned by get() if the environment variable does not exist.
Check if your environment variables' names are correct.
If your problem persists please indicate in which line the error occurs.

Python exchangelib OAuth2 authentication failing

Since Microsoft has apparently EOL'd basic authentication for Exchange Web Services, I'm trying to convert my Python app to use OAuth2. Python 3.8, exchangelib 3.2.1, ms-exchange version unknown but recent. Relevant code follows:
from exchangelib import Credentials, Account, Message, Mailbox, ExtendedProperty, Configuration, \
OAuth2Credentials, OAuth2AuthorizationCodeCredentials, Identity, OAUTH2
from oauthlib.oauth2 import OAuth2Token
credentials = OAuth2Credentials(client_id="xxxxxxxx-xxxx-etc", client_secret="xxxxxxxxxxxxx-etc",
tenant_id="xxxxxxxx-xxxx-etc")
config=Configuration(credentials=credentials, auth_type=OAUTH2)
acct = Account(primary_smtp_address='testAddr#example.com', config=config, autodiscover=True)
The result:
ValueError: Auth type must be 'OAuth 2.0' for credentials type OAuth2Credentials
DEBUG:exchangelib.protocol:Server autodiscover.example.com: Closing sessions
The exception is being thrown at the beginning of BaseProtocol.create_oauth2_session() in protocol.py:
if self.auth_type != OAUTH2:
raise ValueError('Auth type must be %r for credentials type OAuth2Credentials' % OAUTH2)
Straightforward enough...except that I clearly specified auth_type=OAUTH2 in my code. Eventually I discovered that a second Configuration object is being created; the first with type OAUTH2 as expected, the second with type NTLM, and that's the one that create_oauth2_session is failing on. The second instance is carrying my credentials, but the service endpoint argument changes from None to autodiscover.example.com/Autodiscover/Autodiscover.xml. This makes sense as part of the autodiscover process (I think,) but why the second instance, and why is it changing the auth type?? I'm stumped. Any/all help is greatly appreciated.
This looks like a bug. This commit should have allowed OAuth for autodiscover but it apparently doesn't work for you. I would break out a debugger and find out where the auth_type value is getting reset. I don't have an OAuth-enabled EWS server, so I can't test this myself.

Google Cloud Endpoints Python Quickstart echo sample issue

In the python standard environment quickstart, the endpoints method test_api_key returns a 503 Service Unavailable. The error occurs in the API Explorer when run with dev_appser.py and when the API is deployed. The code for it is:
import endpoints
from protorpc import message_types
from protorpc import messages
from protorpc import remote
class TestResponse(messages.Message):
content = messages.StringField(1)
#endpoints.api(name='practice', version='v1', description='My Practice API')
class PracticeApi(remote.Service):
#endpoints.method(
message_types.VoidMessage,
TestResponse,
path='test/getApiKey',
http_method='GET',
name='test_api_key')
def test_api_key(self, request):
return TestResponse(content=request.get_unrecognized_field_info('key'))
api = endpoints.api_server([PracticeApi])
I don't have a good understanding of .get_unrecognized_field_info('key') so I am not sure what the issue is? Thanks.
Firstly, I recommend reading Google Protocol RPC Library Overview, since it's Google Cloud Endpoints uses it extensively.
#endpoints.method allows you to configure a specific method in your API. Configuration options are documented in Google Cloud Platform documentation Creating an API with Cloud Endpoints Frameworks for App Engine, in the section, Defining an API method (#endpoints.method).
If you're restricting access to the test/getApiKey/test_api_key method, then you must configure the method with the api_key_required=True option. Restricting API Access with API Keys (Frameworks) discusses that further, but your method annotation should be:
#endpoints.method(
message_types.VoidMessage,
TestResponse,
path='test/getApiKey',
http_method='GET',
name='test_api_key',
api_key_required=True
)
Notice your method accepts a request parameter representing the HTTP request (i.e. client using your API):
def test_api_key(self, request):
However, the request parameter is actually Google Protocol RPC Message (Proto RPC) Message object and as such is very well defined. If additional fields exist in the ProtoRPC request parameter, beyond what is formally defined, they are still stored with the request object but must be retrieved using the following method:
def get_unrecognized_field_info(self, key, value_default=None,
variant_default=None):
"""Get the value and variant of an unknown field in this message.
Args:
key: The name or number of the field to retrieve.
value_default: Value to be returned if the key isn't found.
variant_default: Value to be returned as variant if the key isn't
found.
Returns:
(value, variant), where value and variant are whatever was passed
to set_unrecognized_field.
"""
Message class code on GitHub is quite well documented. .
No arguments will appear in the body of a request because you've configured the method with to be called with HTTP GET:
http_method='GET'
...you're correctly using the value message_types.VoidMessage.
In terms of your error, 503 is just a generic server error, can you provide any information from the StackDriver logs? They will point you to the exact line and error in your code.
There were three things that were creating the 503 error.
Firstly, I needed to make the method or entire Api require an Api Key. In this case I just applied it to the entire Api:
#endpoints.api(name='practice', version='v1', api_key_required=True)
class PracticeApi(remote.Service):
Secondly, after I generated the Api Key in the cloud console I needed to put the Key into the openapi.json file before deploying it.
Lastly, I was still getting a validation error:
ValidationError: Expected type <type 'unicode'> for field content, found (u'My Api Key', Variant(STRING, 9)) (type <type 'tuple'>)
The get_unrecognized_field_info() function returns a tuple of (value, variant). A tuple was not expected by the response so I updated the method to only show value:
def test_api_key(self, request):
return TestResponse(content=request.get_unrecognized_field_info('key')[0])

How to attach file via "Bugzilla XMLRPC access module"

I am working on bugzilla xml-rpc by using "Bugzilla XMLRPC access module" developed in python.
How I can attach/download bugzilla file by using this module ?
According to guideline of API get_attachments_by_bug($bug_id) retrieves and returns the attachments.
But this function didn't worked for me, I got following error message.
<type 'exceptions.AttributeError'>: 'Bugzilla4' object has no attribute 'get_attachments_by_bug'
Any help would be appreciated.
FYI:
I am in contact with supplier of python-bugzilla tool and here I got response from them.
"Not all bugzilla XMLRPC APIs are wrapped by python-bugzilla, that's one of them.
The 'bugzilla' command line tool that python-bugzilla ships has commands for
attaching files and downloading attachments, take a look at the code there for
guidance."
I've figured out the way how to download/upload attachment by using "Bugzilla XMLRPC access module"
you need to pass the id of attached file as parameter to the following function
Download:
downloaded_file = bz.download_attachment(attachment_id)
file_name = str(downloaded_file.name)
Upload:
kwards = {
'contenttype':'application/octet-stream',
# 'filename': file_path #there could be more parameters if needed
}
#attachfile method will return the id of attached file
bz.attachfile(bug_id, file_path, file_name, **kwards)
However attached file got corrupted due to some xmp-rpc API's internal methods described here, here and here, that's another issue :)

Categories