Server returning 404 error while consuming functions of BSE SOAP Apis - python-3.x

I was integrating bsestar mf soap api's with django. So in order to consume soap apis i have use python package called zeep. but after creating its client on its end point and after that whenever i try to run soap functions it says 404 error.
my code :
import zeep
def soap_set_wsa_headers(method_url, svc_url):
header = zeep.xsd.Element(
"Header",
zeep.xsd.ComplexType(
[
zeep.xsd.Element(
"{http://www.w3.org/2005/08/addressing}Action", zeep.xsd.String()
),
zeep.xsd.Element(
"{http://www.w3.org/2005/08/addressing}To", zeep.xsd.String()
),
]
),
)
header_value = header(Action=method_url, To=svc_url)
return header_value
WSDL_ORDER_URL = [
'https://bsestarmfdemo.bseindia.com/MFOrderEntry/MFOrder.svc?singleWsdl',
'https://www.bsestarmf.in/MFOrderEntry/MFOrder.svc?singleWsdl'
]
SVC_ORDER_URL = [
'https://bsestarmfdemo.bseindia.com/MFOrderEntry/MFOrder.svc',
'https://www.bsestarmf.in/MFOrderEntry/MFOrder.svc'
]
METHOD_ORDER_URL = [
'https://bsestarmfdemo.bseindia.com/MFOrderEntry/',
'https://bsestarmf.in/MFOrderEntry/'
]
WSDL_UPLOAD_URL = [
'https://bsestarmfdemo.bseindia.com/MFUploadService/MFUploadService.svc?singleWsdl',
'https://www.bsestarmf.in/StarMFWebService/StarMFWebService.svc?singleWsdl'
]
SVC_UPLOAD_URL = [
'https://bsestarmfdemo.bseindia.com/MFUploadService/MFUploadService.svc/Basic',
'https://www.bsestarmf.in/StarMFWebService/StarMFWebService.svc/Basic'
]
METHOD_UPLOAD_URL = [
'https://bsestarmfdemo.bseindia.com/2016/01/IMFUploadService/',
'https://www.bsestarmf.in/2016/01/IStarMFWebService/'
]
client = zeep.Client(wsdl=WSDL_ORDER_URL[0])
method_url = METHOD_UPLOAD_URL[0] + 'getPassword'
svc_url = SVC_UPLOAD_URL[0]
header_value=soap_set_wsa_headers(method_url,svc_url)
client.service.getPassword(UserId='3081801',
Password='Abc4231',
PassKey='anything',
_soapheaders=[header_value])
Error while calling getPassword function:
zeep.transports: HTTP Post to
https://bsestarmfdemo.bseindia.com/MFOrderEntry/MFOrder.svc:
<?xml version='1.0' encoding='utf-8'?>
<soap-env:Envelope xmlns:soap-env="http://www.w3.org/2003/05/soap-envelope"><soap-env:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><Header><wsa:Action>https://bsestarmfdemo.bseindia.com/2016/01/IMFUploadService/getPassword</wsa:Action><wsa:To>https://bsestarmfdemo.bseindia.com/MFUploadService/MFUploadService.svc/Basic</wsa:To></Header><wsa:Action>http://bsestarmf.in/MFOrderEntry/getPassword</wsa:Action><wsa:MessageID>urn:uuid:953b29c6-a2a0-48a0-aef0-5d4f1547b39a</wsa:MessageID><wsa:To>https://bsestarmfdemo.bseindia.com/MFOrderEntry/MFOrder.svc</wsa:To></soap-env:Header><soap-env:Body><ns0:getPassword xmlns:ns0="http://bsestarmf.in/"><ns0:UserId>3081801</ns0:UserId><ns0:Password>Abc4231</ns0:Password><ns0:PassKey>kuchbhi</ns0:PassKey></ns0:getPassword></soap-env:Body></soap-env:Envelope>
zeep.transports: HTTP Response from https://bsestarmfdemo.bseindia.com/MFOrderEntry/MFOrder.svc (status: 404):
---------------------------------------------------------------------------
TransportError Traceback (most recent call last)
<ipython-input-64-b5411107d6e5> in <module>
----> 1 client.service.getPassword(UserId='3081801',
2 Password='Abc4231',
3 PassKey='kuchbhi',
4 _soapheaders=[header_value])
/opt/anaconda3/lib/python3.8/site-packages/zeep/proxy.py in __call__(self, *args, **kwargs)
44 kwargs["_soapheaders"] = soap_headers
45
---> 46 return self._proxy._binding.send(
47 self._proxy._client,
48 self._proxy._binding_options,
/opt/anaconda3/lib/python3.8/site-packages/zeep/wsdl/bindings/soap.py in send(self, client, options, operation, args, kwargs)
133 return response
134
--> 135 return self.process_reply(client, operation_obj, response)
136
137 async def send_async(self, client, options, operation, args, kwargs):
/opt/anaconda3/lib/python3.8/site-packages/zeep/wsdl/bindings/soap.py in process_reply(self, client, operation, response)
179
180 elif response.status_code != 200 and not response.content:
--> 181 raise TransportError(
182 u"Server returned HTTP status %d (no content available)"
183 % response.status_code,
TransportError: Server returned HTTP status 404 (no content available)
Thanks in advance :)

Related

I want to know how to read the value of headers in SetTask class after configuring tasks = [SetTask]?

from locust import HttpUser, task, between,SequentialTaskSet,TaskSet,User,events
import json
#events.test_start.add_listener
def on_start(**kwargs):
print("A test will start...")
#events.test_stop.add_listener
def on_stop(**kwargs):
print("A test is ending...")
class SetTask(TaskSet):
#task
def getLogDetail(self):
deatil_url = "/auth/online?page=0&size=10&sort=id%2Cdesc"
with self.client.request(method='GET',
url=deatil_url,
headers=self.headers,
name='get log detail') as response:
print(response.text)
class FlaskTask(SequentialTaskSet):
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
def on_start(self):
res = self.client.request(method='GET', url="/auth/code",name="get code")
uuid = res.json()['uuid']
headers = {
"content-type": "application/json;charset=UTF-8",
}
datda_info = {
"code": "8",
"password": "B0GdcVWB+XtTwsyBjzoRkn8VnSgtPVKpl8mp7AuQ+BTeU030grUkRwmOHXFCjEhKXB7yezBS7dFEJ63ykR2piQ==",
"username": "admin",
"uuid": uuid
}
with self.client.request(method='POST',url="/auth/login", headers=headers, catch_response=True,data=json.dumps(datda_info),name="get token") as response:
self.token = response.json()['token']
if response.status_code == 200:
self.token = response.json()['token']
response.success()
else:
response.failure("get token failed")
self.headers = {
"Authorization": self.token
}
tasks = [SetTask]
#task
def getUserDetail(self):
deatil_url = "/api/dictDetail?dictName=user_status&page=0&size=9999"
with self.client.request(method='GET',
url=deatil_url,
headers=self.headers,
name='get user detail') as response:
print(response.text)
def function_task():
print("This is the function task")
class FlaskUser(HttpUser):
host = 'http://192.168.31.243:8888'
wait_time = between(1,3)
tasks = [FlaskTask,function_task]
I got error:
A test will start...
[2022-03-26 00:04:56,146] wangguilin/INFO/locust.runners: Ramping to 1 users at a rate of 1.00 per second
[2022-03-26 00:04:56,147] wangguilin/INFO/locust.runners: All users spawned: {"FlaskUser": 1} (1 total users)
[2022-03-26 00:04:56,148] wangguilin/ERROR/locust.user.task: function_task() takes 0 positional arguments but 1 was given
Traceback (most recent call last):
File "c:\users\Users\pycharmprojects\testlocust\venv\lib\site-packages\locust\user\task.py", line 319, in run
self.execute_next_task()
File "c:\users\Users\pycharmprojects\testlocust\venv\lib\site-packages\locust\user\task.py", line 344, in execute_next_task
self.execute_task(self._task_queue.pop(0))
File "c:\users\Users\pycharmprojects\testlocust\venv\lib\site-packages\locust\user\task.py", line 457, in execute_task
task(self.user)
TypeError: function_task() takes 0 positional arguments but 1 was given
[2022-03-26 00:04:58,154] wangguilin/ERROR/locust.user.task: 'SetTask' object has no attribute 'headers'
Traceback (most recent call last):
File "c:\users\Users\pycharmprojects\testlocust\venv\lib\site-packages\locust\user\task.py", line 319, in run
self.execute_next_task()
File "c:\users\Users\pycharmprojects\testlocust\venv\lib\site-packages\locust\user\task.py", line 344, in execute_next_task
self.execute_task(self._task_queue.pop(0))
File "c:\users\Users\pycharmprojects\testlocust\venv\lib\site-packages\locust\user\task.py", line 356, in execute_task
task(self)
File "C:\Users\Users\PycharmProjects\testlocust\locustflask.py", line 22, in getLogDetail
headers=self.headers,
AttributeError: 'SetTask' object has no attribute 'headers'
Traceback (most recent call last):
File "c:\users\Users\pycharmprojects\testlocust\venv\lib\site-packages\gevent_ffi\loop.py", line 270, in python_check_callback
def python_check_callback(self, watcher_ptr): # pylint:disable=unused-argument
question:
I want to know how to read the value of headers in SetTask class after configuring tasks = [SetTask]?
my locust version is: 2.8.3
So can parameters be passed in this case?

Specifying ConnectionProperties When Creating New Connection in Boto3

I'm trying to create a connection using a boto3 python script. It's a connection to a mysql database on an ec2 instance. I'm using the script below. I'm getting the error message below. I'm not sure what I'm missing. I've used similar scripts to create glue crawlers without issue. I'm pretty much following the boto3 documentation except I added username and password in the ConnectionProperties. I'm not sure if that's correct. Can someone please let me know if I'm doing this right, or else what I need to fix in my code?
code:
# create new connection
response = client.create_connection(
ConnectionInput={
'Name': 'tst_scrpt',
'ConnectionType': 'JDBC',
'ConnectionProperties': {
'string': 'jdbc:mysql://dataxxx:3306/disxxx',
'username':'root',
'password':'ip1k5PNCxxxxx'
}
,
'PhysicalConnectionRequirements': {
'SubnetId': 'subnet-0436167b7cbxxxx',
'SecurityGroupIdList': [
'sg-02c3f45ce51exxxxx'
]
}
}
)
Error:
---------------------------------------------------------------------------
InvalidInputException Traceback (most recent call last)
<ipython-input-18-6ac0bdcfa816> in <module>
16 'SubnetId': 'subnet-0436167b7cbxxxx',
17 'SecurityGroupIdList': [
---> 18 'sg-02c3f45ce51exxxxx'
19 ]
20 # ,
/anaconda3/envs/py36/lib/python3.6/site-packages/botocore/client.py in _api_call(self, *args, **kwargs)
355 "%s() only accepts keyword arguments." % py_operation_name)
356 # The "self" in this scope is referring to the BaseClient.
--> 357 return self._make_api_call(operation_name, kwargs)
358
359 _api_call.__name__ = str(py_operation_name)
/anaconda3/envs/py36/lib/python3.6/site-packages/botocore/client.py in _make_api_call(self, operation_name, api_params)
659 error_code = parsed_response.get("Error", {}).get("Code")
660 error_class = self.exceptions.from_code(error_code)
--> 661 raise error_class(parsed_response, operation_name)
662 else:
663 return parsed_response
InvalidInputException: An error occurred (InvalidInputException) when calling the CreateConnection operation: Validation for connection properties failed
I had the ConnectionProperties wrong. replace 'string' with 'JDBC_CONNECTION_URL'. The correction is below.
'ConnectionProperties': {
'JDBC_CONNECTION_URL': 'jdbc:mysql://dataxxx:3306/disxxx',
'username':'root',
'password':'ip1k5PNCxxxxx'
}

Python Elasticsearch 7.05 indexing failing

I have created an index on my ES server via Kibana that looks like this
PUT export_control
{
"mappings": {
"properties": {
"content": {
"type": "text",
"term_vector": "with_positions_offsets"
}
}
}
}
Result is
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "export_control"
}
When I try to index a new document with the following command in python
col_names = df.columns
for row_number in range(df.shape[0]):
body = dict([(name, str(df.iloc[row_number][name])) for name in col_names])
es.index(index = 'export_control', doc_type="pdf_document", body = body)
I get the following error
RequestError Traceback (most recent call last)
<ipython-input-247-6df868fd60f1> in <module>
2 for row_number in range(df.shape[0]):
3 body = dict([(name, str(df.iloc[row_number][name])) for name in col_names])
----> 4 es.index(index = 'export_control', doc_type="pdf_document", body = body)
/usr/local/lib/python3.7/site-packages/elasticsearch/client/utils.py in _wrapped(*args, **kwargs)
74 for p in es_query_params + GLOBAL_PARAMS:
75 if p in kwargs:
---> 76 v = kwargs.pop(p)
77 if v is not None:
78 params[p] = _escape(v)
/usr/local/lib/python3.7/site-packages/elasticsearch/client/__init__.py in index(self, index, doc_type, body, id, params)
317 "timeout",
318 "timestamp",
--> 319 "ttl",
320 "version",
321 "version_type",
/usr/local/lib/python3.7/site-packages/elasticsearch/transport.py in perform_request(self, method, url, headers, params, body)
316 method = "POST"
317
--> 318 # or as source parameter
319 elif self.send_get_body_as == "source":
320 if params is None:
/usr/local/lib/python3.7/site-packages/elasticsearch/connection/http_urllib3.py in perform_request(self, method, url, params, body, timeout, ignore, headers)
183 kw.update(
184 {
--> 185 "cert_reqs": "CERT_REQUIRED",
186 "ca_certs": ca_certs,
187 "cert_file": client_cert,
/usr/local/lib/python3.7/site-packages/elasticsearch/connection/base.py in _raise_error(self, status_code, raw_data)
123 )
124 logger.debug("> %s", body)
--> 125 logger.debug("< %s", response)
126
127 self._log_trace(method, path, body, status_code, response, duration)
RequestError: TransportError(400, 'illegal_argument_exception', 'Rejecting mapping update to [export_control] as the final mapping would have more than 1 type: [_doc, pdf_document]')
The problem is that in Elasticsearch types were removed recently - some full definition of it, which means, that you could have only one type - called _doc, while you're creating second one - pdf_document.
You should use
es.index(index = 'export_control', doc_type="_doc", body = body)

Not able to upload file using slack api files.upload

This question may seem duplicate but I have tried a lot but did not get success.
I am trying to upload html file using https://slack.com/api/files.upload API but I am getting below error always.
response
{'ok': False, 'error': 'no_file_data'}
I went through documentation [a link]https://api.slack.com/methods/files.upload and tried with different options but still i am getting the same response {'ok': False, 'error': 'no_file_data'}
Also i have seen many similar questions in stack overflow but none of them resolved the problem.
[a link]no_file_data error when using Slack API upload
[a link]How to upload files to slack using file.upload and requests
Below is my code.
import requests
def post_reports_to_slack(html_report):
"""
"""
url = "https://slack.com/api/files.upload"
# my_file = {html_report, open(html_report, 'rb'), 'html'}
data = {
"token": bot_user_token,
"channels": channel_name,
"file": html_report,
"filetype": "html"
}
# data = "token=" + bot_user_token + \
# "&channels=" + channel_name +\
# "&file=" + html_report + "&filetype=" + "html"
response = requests.post(
url=url, data=data,
headers={"Content-Type": "application/x-www-form-urlencoded"})
print("response", response)
print(response.json())
if response.status_code == 200:
print("successfully completed post_reports_to_slack "
"and status code %s" % response.status_code)
else:
print("Failed to post report on slack channel "
"and status code %s" % response.status_code)
Please help to resolve the issue.
I was needed to add "content" argument and "filename" argument instead of "file" argument in files.upload API payload, Now file uploading to slack channel is working fine.
import requests
def post_reports_to_slack(html_report):
url = "https://slack.com/api/files.upload"
with open(html_report) as fh:
html_data = fh.read()
data = {
"token": bot_user_token,
"channels": "#channel_name",
"content": html_data,
"filename": "report.html",
"filetype": "html",
}
response = requests.post(
url=url, data=data,
headers={"Content-Type": "application/x-www-form-urlencoded"})
if response.status_code == 200:
print("successfully completed post_reports_to_slack "
"and status code %s" % response.status_code)
else:
print("Failed to post report on slack channel "
"and status code %s" % response.status_code)

Google Adwords Traffic Estimator Service and Python

I've downloaded a code sample that looks for particular keywords and pulls some metrics. I've noticed a lot of Google Adwords API examples are compliant with python 3.x so I'm wondering if there is an issue with that? See below for code sample:
from googleads import adwords
def main(client):
# Initialize appropriate service.
traffic_estimator_service = client.GetService(
'TrafficEstimatorService', version='v201609')
# Construct selector object and retrieve traffic estimates.
keywords = [
{'text': 'mars cruise', 'matchType': 'BROAD'},
{'text': 'cheap cruise', 'matchType': 'PHRASE'},
{'text': 'cruise', 'matchType': 'EXACT'}
]
negative_keywords = [
{'text': 'moon walk', 'matchType': 'BROAD'}
]
keyword_estimate_requests = []
for keyword in keywords:
keyword_estimate_requests.append({
'keyword': {
'xsi_type': 'Keyword',
'matchType': keyword['matchType'],
'text': keyword['text']
}
})
for keyword in negative_keywords:
keyword_estimate_requests.append({
'keyword': {
'xsi_type': 'Keyword',
'matchType': keyword['matchType'],
'text': keyword['text']
},
'isNegative': 'true'
})
# Create ad group estimate requests.
adgroup_estimate_requests = [{
'keywordEstimateRequests': keyword_estimate_requests,
'maxCpc': {
'xsi_type': 'Money',
'microAmount': '1000000'
}
}]
# Create campaign estimate requests.
campaign_estimate_requests = [{
'adGroupEstimateRequests': adgroup_estimate_requests,
'criteria': [
{
'xsi_type': 'Location',
'id': '2840' # United States.
},
{
'xsi_type': 'Language',
'id': '1000' # English.
}
],
}]
# Create the selector.
selector = {
'campaignEstimateRequests': campaign_estimate_requests,
}
# Optional: Request a list of campaign-level estimates segmented by
# platform.
selector['platformEstimateRequested'] = True
# Get traffic estimates.
estimates = traffic_estimator_service.get(selector)
campaign_estimate = estimates['campaignEstimates'][0]
# Display the campaign level estimates segmented by platform.
if 'platformEstimates' in campaign_estimate:
platform_template = ('Results for the platform with ID: "%d" and name: '
'"%s".')
for platform_estimate in campaign_estimate['platformEstimates']:
platform = platform_estimate['platform']
DisplayEstimate(platform_template % (platform['id'],
platform['platformName']),
platform_estimate['minEstimate'],
platform_estimate['maxEstimate'])
# Display the keyword estimates.
if 'adGroupEstimates' in campaign_estimate:
ad_group_estimate = campaign_estimate['adGroupEstimates'][0]
if 'keywordEstimates' in ad_group_estimate:
keyword_estimates = ad_group_estimate['keywordEstimates']
keyword_template = ('Results for the keyword with text "%s" and match '
'type "%s":')
keyword_estimates_and_requests = zip(keyword_estimates,
keyword_estimate_requests)
for keyword_tuple in keyword_estimates_and_requests:
if keyword_tuple[1].get('isNegative', False):
continue
keyword = keyword_tuple[1]['keyword']
keyword_estimate = keyword_tuple[0]
DisplayEstimate(keyword_template % (keyword['text'],
keyword['matchType']),
keyword_estimate['min'], keyword_estimate['max'])
def _CalculateMean(min_est, max_est):
if min_est and max_est:
return (float(min_est) + float(max_est)) / 2.0
else:
return None
def _FormatMean(mean):
if mean:
return '%.2f' % mean
else:
return 'N/A'
def DisplayEstimate(message, min_estimate, max_estimate):
"""Displays mean average cpc, position, clicks, and total cost for estimate.
Args:
message: str message to display for the given estimate.
min_estimate: sudsobject containing a minimum estimate from the
TrafficEstimatorService response.
max_estimate: sudsobject containing a maximum estimate from the
TrafficEstimatorService response.
"""
# Find the mean of the min and max values.
mean_avg_cpc = (_CalculateMean(min_estimate['averageCpc']['microAmount'],
max_estimate['averageCpc']['microAmount'])
if 'averageCpc' in min_estimate else None)
mean_avg_pos = (_CalculateMean(min_estimate['averagePosition'],
max_estimate['averagePosition'])
if 'averagePosition' in min_estimate else None)
mean_clicks = _CalculateMean(min_estimate['clicksPerDay'],
max_estimate['clicksPerDay'])
mean_total_cost = _CalculateMean(min_estimate['totalCost']['microAmount'],
max_estimate['totalCost']['microAmount'])
print (message)
print ('Estimated average CPC: %s' % _FormatMean(mean_avg_cpc))
print ('Estimated ad position: %s' % _FormatMean(mean_avg_pos))
print ('Estimated daily clicks: %s' % _FormatMean(mean_clicks))
print ('Estimated daily cost: %s' % _FormatMean(mean_total_cost))
if __name__ == '__main__':
# Initialize client object.
adwords_client = adwords.AdWordsClient.LoadFromStorage()
main(adwords_client)
Here is the error message:
(Money) not-found
path: "Money", not-found
(Keyword) not-found
path: "Keyword", not-found
(Keyword) not-found
path: "Keyword", not-found
(Keyword) not-found
path: "Keyword", not-found
(Keyword) not-found
path: "Keyword", not-found
(Location) not-found
path: "Location", not-found
(Language) not-found
path: "Language", not-found
<suds.sax.document.Document object at 0x03BF1D10>
Server raised fault in response.
Traceback (most recent call last):
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\site-packages\suds\transport\http.py", line 82, in send
fp = self.u2open(u2request)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\site-packages\suds\transport\http.py", line 132, in u2open
return url.open(u2request, timeout=tm)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\urllib\request.py", line 472, in open
response = meth(req, response)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\urllib\request.py", line 582, in http_response
'http', request, response, code, msg, hdrs)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\urllib\request.py", line 510, in error
return self._call_chain(*args)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\urllib\request.py", line 444, in _call_chain
result = func(*args)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\urllib\request.py", line 590, in http_error_default
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 500: Internal Server Error
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\site-packages\suds\client.py", line 613, in send
reply = self.options.transport.send(request)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\site-packages\suds\transport\http.py", line 94, in send
raise TransportError(e.msg, e.code, e.fp)
suds.transport.TransportError: Internal Server Error
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\adwords test - Copy (2).py", line 177, in <module>
main(adwords_client)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\adwords test - Copy (2).py", line 95, in main
estimates = traffic_estimator_service.get(selector)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\site-packages\googleads\common.py", line 696, in MakeSoapRequest
raise e
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\site-packages\googleads\common.py", line 692, in MakeSoapRequest
for arg in args])
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\site-packages\suds\client.py", line 521, in __call__
return client.invoke(args, kwargs)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\site-packages\suds\client.py", line 581, in invoke
result = self.send(soapenv)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\site-packages\suds\client.py", line 619, in send
description=tostr(e), original_soapenv=original_soapenv)
File "C:\Users\sfroese\AppData\Local\Programs\Python\Python35-32\lib\site-packages\suds\client.py", line 670, in process_reply
raise WebFault(fault, replyroot)
suds.WebFault: Server raised fault: '[AuthenticationError.CLIENT_CUSTOMER_ID_IS_REQUIRED # ; trigger:'<null>']'
You should set client_customer_id in your googleads.yaml file . you can get client_customer_id from your manager account. go to your manager account and add client then copy your id from upright corner of screen. in googleads.yaml file paste that id to client_customer_id .

Resources