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.
Related
I was trying to make functions to save, get, and get all for the Replit Python database. It doesn't work and I can't find out why.
Get all function:
def loadAll(user):
if user in db.keys():
return db[user]
if user not in db.keys():
db[user] = {}
return db[user]
It throws an error at return db[user].
This is the code that fires the function (I'm using the discord.py commands extension.):
#bot.command(name = "getMyData")
async def getUserData(ctx):
await ctx.send(ctx.author)
await ctx.send(loadAll(ctx.author))
The error message says:
TypeError: quote_from_bytes() expected bytes
I solved it by changing the database key to not just be the user.
Replit Database doesn't support integers as keys. Stringify the key beforehand.
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
So I'm making an rpg type game in Discord.py Rewrite and when the bot is ready, i run this code and I get the error "json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)"
#client.event
async def on_ready():
global userdata
try:
with open('userdata.json') as f:
userdata = json.load(f)
except FileNotFoundError:
print("Could not load userdata.json")
userdata = {}
The error you see will be thrown when reading in incorrect files.
Thus the problem is most likely the fact that you dont have content in your JSON file, or have created an incorrect JSON file.
To solve this problem you need to put correct json in the file you want to load.
As #Poojan said you can do the following (to stop it throwing errors):
{
}
In order to test if your json file is correct, I recommend using this site: jsonlint.
Write {} in your JSON file and save and run the code
I am trying to extract outlook email body, recipient address, subject and received date.
I was able to extract subject and received date but unable to extract body and recipient address:
Below is my code for subject and received date:
outlook = win32com.client.Dispatch('Outlook.Application').GetNamespace('MAPI')
namespace = outlook.Session
recipient = namespace.CreateRecipient("abc#xyz.com")
inbox = outlook.GetSharedDefaultFolder(recipient, 6)
messages = inbox.Items
email_subject = []
email_date = []
email_date_time = []
for x in messages:
sub = x.Subject
received_date = x.senton.date()
received_date_time = str(x.ReceivedTime)
email_subject.append(sub)
email_date.append(received_date)
email_date_time.append(received_date_time)
For body i am trying:
for x in messages:
body = x.Body
print(body)
but this is not working and i am getting the error below:
Traceback (most recent call last):
File "<ipython-input-85-d79967933b99>", line 2, in <module>
sub = x.Body
File "C:\ProgramData\Anaconda3\lib\site-packages\win32com\client\dynamic.py", line 516, in __getattr__
ret = self._oleobj_.Invoke(retEntry.dispid,0,invoke_type,1)
com_error: (-2147467259, 'Unspecified error', None, None)
I've just run similar code on my computer, in an inbox with 3,000+ items of mixed type (skype message notifications, calendar invites/notifications, emails, etc.) and I cannot replicate this error, even for items where not m.Body -- I thought that was a possible culprit, maybe a certain type of item doesn't have a body would throw an error -- but that appears to not be the case:
>>> for m in messages:
... if not m.body:
... print(m.Subject)
... print(m.Body)
...
Accepted: Tables discussion
Message Recall Failure: tables/ new data status
Message Recall Failure: A few issues with the data
You should probably add a print(m.Class) because I still think that maybe certain types of items do not have a Body property.
This thread suggests that there may be a user/security setting that prevents programmatic access to Outlook, so you might want to double-check on that (though I think if not allowed, none of your code would work -- still, worth looking in to!).
I have figured out the source of this error. We are running into issues with the comObjectModelGaurd. Our group policy recently changed to disallow programatic access to protected mailItem objects.
Modifying Outlook Users Trust settings or the registry will fix the problem.
Since I can't replicate the error, perhaps I can still help you debug and identify the source of the problem, from which we can probably come up with a good solution.
Use a function to get the item's body, and use try/except to identify which items are causing error.
def getBody(m):
s = ""
try:
s = m.Body
except COMError:
s = '\t'.join(('Error!', m.Class, m.senton.date(), m.Subject))
return s
for m in messages:
print(getBody(m))
I think that I found a solution that worked. For me it was an issue with permissions, but I made the registry edits in https://www.slipstick.com/developer/change-programmatic-access-options/ and it worked a treat.
EDIT: I think this worked by unblocking some lower level permissions that enabled an outside program to access the outlook client.
Recalled Emails would have no Body hence we can find that via the MessageClass and exclude that particular Class
for i in messages:
if email.MessageClass != "IPM.Outlook.Recall":
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.