Pass an array to web service SUDS (Jurko) - python

I know I'm probably doing something pretty stupid or small (I hope) but what I'm doing is passing suds an array of data but all I'm getting is this error.
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 http://tempuri.org/:tankLevelDataArray. The InnerException message was 'Error in line 1 position 407. Expecting state 'Element'.. Encountered 'Text' with name '', namespace ''. '. Please see InnerException for more details.'
No matter what I try my program will keep getting this issue, this is my code that I am currently using to pass it the array.
def PosEncodedTankData( Id, encodedTankData ):
global HOST2
global PORT2
global DATA
date = datetime.datetime.now()
#Setup Soap
client = Client(HOST2)
try:
#Send data
print (client)
tankLevelDataArray = client.factory.create('tankLevelDataArray')
tankLevelDataArray = np.array(sortData(DATA, 21, tankLevelDataArray))
client.service.PostTankDataArray (1, tankLevelDataArray)
print ("Message Recieved")
except TimeoutError:
print ("Message was not sent")
So when go through that method is just fails.. But I haven't been able to figure out what is happening.
I am passing a array of arrays.

Nevermind everyone, looks like the array needed was an array of TankLevelData and I was just giving it integers therefor causing my error. My bad.

Related

Azure Function Python - serviceBusTrigger - How to deadletter a message

I have a plain simple Python function which should dead-letter a message if it does not match few constraint. Actually I'm raising an exception and everything works fine (I mean the message is being dead-lettered), but I would like to understand if there is a "clean" way to dead-letter the message without raising an exception.
async def function_handler(message: func.ServiceBusMessage, starter: str):
for msg in [message]:
client = df.DurableOrchestrationClient(starter)
message_body = msg.get_body().decode("utf-8")
msg = json.loads(message_body)
if 'valid' in msg:
instance_id = await client.start_new('orchestrator', None, json.dumps(message_body))
else:
raise Exception(f'not found valid {msg["id"]}')
This is part of host.json, this should indicate I'm working with version 2.0 of Azure Functions
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[2.*, 3.0.0)"
},
Suggestions are welcome
At time of writing, in Python it is not possible interactively send a message in dead-letter.
I found out that autocomplete=false is only supported for C#.
This basically means that the only way to dead letter a message is raise an exception, just like I was doing in my code.
Thanks to #GauravMantri to pointing me the right way (i.e. have a look at how to use the autocomplete configuration parameter).
Azure Service Bus Queue has this Max Delivery Count property that you can make use of. Considering you only want to process a message exactly once and then deadletter the message in case Function is unable to process, what you can do is set the max delivery count to 1. That way the message will be automatically deadlettered after 1st delivery.
By default, Function runtime tries to auto-complete the message if there is no exception in processing the message. You do not want Function runtime to do that. For that what you would need to do is set auto complete setting to false. However if the message is processed successfully, you would want to delete that message thus you will need to call auto complete manually if the message processing is successful.
Something like:
if 'valid' in msg:
instance_id = await client.start_new('orchestrator', None, json.dumps(message_body))
//auto complete the message here...
else:
//do nothing and the message will be dead-lettered

Google Analytics Python API call resulting in UnboundLocalError

I have a python script that calls the google analytics api once for everyday that I'm trying to get data for. However, on some calls I'm apparently receiving nothing. That or I'm handling errors incorrectly. Here is the function that I'm using to call the api.
def run_query(hour_in_dim, start_date, sessions_writer, connection_error_count, pageToken=None):
# Try to run api request for one day. Wait 10 seconds if "service is currently unavailable."
try:
traffic_results = get_api_query(analytics, start_date, start_date, pageToken)
except HttpError as err:
if err.resp.status in [503]:
print("Sleeping, api service temporarily unavailable.")
time.sleep(10)
run_query(hour_in_dim, start_date, sessions_writer, connection_error_count, pageToken)
else:
raise
except ConnectionResetError:
connection_error_count += 1
time.sleep(10)
if connection_error_count > 2:
raise
else:
run_query(hour_in_dim, start_date, sessions_writer, connection_error_count, pageToken)
# TODO: solve random occurances of "UnboundLocalError: local variable 'traffic_results' referenced before assignment"
dimensions_ga = traffic_results['reports'][0]['columnHeader']['dimensions']
rows = traffic_results['reports'][0]['data']['rows']
The Unbound Local Error is coming from the second line from the bottom where I call traffic results and try to assign it to the dimensions_ga variable.
I believe the problem is that I was using recursion instead of a loop. I used the sample code provided here:
https://developers.google.com/analytics/devguides/reporting/core/v3/errors
also changing "except HttpError, error:" to "except HttpError as error" for python 3.
Not sure the best way to test this, as error is not manually reproducible..

Python Telegram bot - KeyError after running for a few hours

I wrote a Telegram bot in Python, which is running on my Raspberry Pi (Raspbian). I eventually see an error after the bot has been running for a few hours.
Before I post the complete code, could someone please help me understand the error? I would like to run the bot indefinitely, or at least for multiple days, before I need to restart it.
The error is as follows:
Traceback (most recent call last):
File "/home/pi/Schreibtisch/StreamrPreisBot/telepot/loop.py", line 37, in run_forever
self._handle(msg)
File "/home/pi/Schreibtisch/StreamrPreisBot/streamrinfobot.py", line 32, in handle
command = msg['text']
KeyError: 'text'
Edit:
Following code is used:
def handle(msg):
chat_id = msg['chat']['id']
command = msg['text']
Might this code solve the problem?
def handle(msg):
chat_id = msg['chat']['id']
command = msg.get('text')
Error says there is no text key inside msg dict. Maybe it's some special telegram message that has no text or there is a bug in you code that delete text key in some cases. You could use
command = msg.get('text')
To get None when there is no text. Or
command = msg.get('text', '')
To get empty string (i.e. '') when there is no text.
You could also check that there is a text inside msg or not with in operator:
if 'text' not in msg:
logger.error('bad message received!')
return
If you want to your service to be always up you should add some mechanism for automatic restart.
like in Python to restart after any error:
while True:
try:
logger.info("Starting bot")
run_bot()
except Exception:
logger.exception("Something bad happened. Restarting")
I also suggest to log errors in a file or services such as Sentry to investigate why there is no text afterwards.
A KeyError is raised when a value is requested from a dict but the key does not exist in the dictionary.
So, in your case, the msg dictionary does not have the key text.
You should inspect your code to ensure that the msg dictionary contains a value associated with the key text. Or, if you expect that msg will sometimes not contain the key text, you should instead access the dictionary with the get method, which never raises a KeyError. See the docs for more information.

Spyne Fault - HTTP Return Codes

I have read information on Spyne Faults (http://spyne.io/docs/2.10/manual/03_types.html), but cant get my head around raising a Fault properly with a 400 Return code. I have the Fault response forming properly, but with a 500 HTTP return code when I have a requirement to return 400.
#srpc(Boolean, _returns=String)
def requestConfiguration(value):
#if value is true, get all the data
if value == True:
#todo - get the config
return 'True Received'
else:
# if anything other than True is received, MUST respond with a SOAP fault and HTTP 400
raise Fault(faultcode="Client.", faultstring="Value must be True")
# raise error.InvalidInputError("problem", "problem")
Reading some of the documentation (http://spyne.io/docs/2.10/modules/spyne/model/fault.html#Fault) , i am interpreting it as the FaultCode must be a string starting with Client and it will return a 400 error. (I know if-else is bad, im just trying to get a proof of concept working before i write the code up properly)
I think i need to subclass the fault instead of just raising it but cant get my head around it. I dived into the code /protocol/soap/soap11 and saw that the fault_to_http_reponse_code simply returns HTTP 500.
Thanks in advance
I gave up on the subclass approach, instead i just updated the fault_to_http_reponse_code function in soap11.py. Its a gross patch but it does the job for what i want.
def fault_to_http_response_code(self, fault):
from spyne.const.http import HTTP_400, HTTP_401, HTTP_404, HTTP_405, HTTP_413, HTTP_500
from spyne.error import Fault, InternalError, ResourceNotFoundError, RequestTooLongError, RequestNotAllowed, InvalidCredentialsError
if isinstance(fault, RequestTooLongError):
return HTTP_413
if isinstance(fault, ResourceNotFoundError):
return HTTP_404
if isinstance(fault, RequestNotAllowed):
return HTTP_405
if isinstance(fault, InvalidCredentialsError):
return HTTP_401
if isinstance(fault, Fault) and (fault.faultcode.startswith('Client.')
or fault.faultcode == 'Client'):
return HTTP_400
return HTTP_500
Then im just raising a normal fault, with the faultcode beginning with Client.
raise Fault(faultcode="Client.", faultstring="value must be True)
Hopfully someone will chip in with the proper approach to this.

How to get response on error in SUDS?

If i have some bad authorization data (for example wrong password) SUDS rises exception (400, u'Bad Request') from which i cant get anything, but in teh log is response, which contains data that password is wrong, but how to get this response? I tried like this:
except Exception as e:
print str(e)
print self._client.last_received()
It prints:
(400, u'Bad Request')
None
But in log there is long xml which contains <SOAP-ENV:Reason><SOAP-ENV:Text xml:lang="en">Sender not authorized</SOAP-ENV:Text></SOAP-ENV:Reason>
I am pulling this out of a comment and into an answer because of the code block.
import suds.client
try:
auth_url = "https://url.to.my.service/authenticator?wsdl"
auth_client = suds.client.Client(auth_url)
cookie = auth_client.service.authenticate(user,password)
except Exception as e:
print str(e)
print auth_client.last_received()
Using this code, I receive the appropriate response from my service if I pass an invalid password:
Server raised fault: 'error.pwd.incorrect'
None
And an appropriate response if I pass an invalid user id:
Server raised fault: 'error.uid.missing'
None
Something you may want to consider doing, is changing your except statement to catch suds.WebFault instead of the generic exception. There may be something else that is occurring and triggering your exception block.
One other thing that may help with your issue, is to pass faults=True in your Client() call.
The Client can be configured to throw web faults as WebFault or to
return a tuple (, )
The code I posted above would look like this:
auth_client = suds.client.Client(auth_url, faults=True)

Categories

Resources