Python 3 error handling running both try and except - python

I am trying to implement error handling in a Python 3 script by getting the SMTPlib library to send an email when it encounters an error like this..
if value.isdigit() :
print ("Value is an integer")
else :
try:
server = smtplib.SMTP(email_server, email_port)
server.ehlo()
server.starttls()
server.login(email_login, email_pass)
server.sendmail("me#example.com", "me#example.com", message)
server.close()
sys.exit()
except:
print ("Error - Was unable to send email")
sys.exit()
This works correctly if the value is an integer, but if it is not then the email gets correctly sent but the Error message is also printed to the screen.
Why is my script running the except section as well?

sys.exit is implemented by raising an exception. When sys.exit is called after server.close, that SystemExit exception is caught.
Here is a little proof:
import sys
try:
print("hello")
sys.exit()
except:
print("exception!")
The basic rules for exception handling were not obeyed. At least except Exception: should have been used. Better except Exception as err: with err logged or printed. And the best approach is to handle only exceptions originating from the SMTP transaction guarded by try/except.

Related

can i raise exception from inside a function in the 'try:' block when client disconnects from the server?

im trying to build a simple server-client chatroom with python socket.
i have the following code:
def handle_connection(client):
while(1):
try:
message = receive_message()
broadcast(message["data"])
except: # for now i don't mind which exception
print("client disconnected")
def receive_message(client_socket):
try:
message_header = client_socket.recv(HEADER)
if len(message_header) == 0:
return False
message_length = int(message_header.decode("utf-8"))
message = client_socket.recv(message_length).decode("utf-8")
return {"header": message_header, "data": message}
except: # most likely will trigger when a client disconnects
return False
where receive_message() calls inside of it to client.recv(HEADER) and returns either False when there is no message, or {"header": msg_header, "data": msg} when everything is ok.
my question is: if client.recv() fails inside of receive_message() due to the client CLI closing, will it raise the exception and print "client disconnected", or not?
i did come up with the following solution i think works:
i defined a function called handle_disconnection() that handles all the content inside of the except in the code above.
def handle_connection(client_socket):
while 1:
try:
message = receive_message()
if not message:
handle_disconnection(client_socket)
break
broadcast(message["data"])
except: # client disconnected
handle_disconnection(client_socket)
break
is this a valid and/or right programming approach to the problem?
if this approach is wrong, how can i handle it correctly?
If client.recv() will raise an exception you will handle it inside of receive_message() and handle_connection() will not receive the exception.
I suggest you to identify situations when you want to control the flow with exceptions or with if-else. I think receive_message() should return a value of message or throw ConnectionError when there are connection issues. In case when there are no messages from the socket you can return None or raise NoMessagesAvailableError.
There is also a rule that tells you should catch specified exceptions, not all of them. Your code will print client disconnected when you are out of memory.

Proper syntax for executing a function only if another function is successful

I have the following code that is part of my email class that I use in my programs. Currently I am running the quit function whether or not a connection to the SMTP server was made in the connect function. I know I could put the quit function inside of the try statement after the email is sent, but I would like to figure out how to write the code to say the equivalent of "if a connection to the server is open, close it." What is the best way to write that in Python?
Thanks!
def connect(self, headers, msg):
try:
self.server.starttls()
try:
self.server.login(self.usrname,self.pswd)
try:
self.server.sendmail(self.sendfrom, self.sendto, headers + "\r\n\r\n" + msg)
except Exception as sendmailfail:
print(sendmailfail)
except Exception as emailfail:
print (emailfail)
except Exception as error:
print(error)
def quit(self):
self.server.quit()
print("The SMTP connection is closed")
first = GmailSmpt('x','y','z','zz')
x , y = first.message()
first.connect(x,y)
first.quit()
You need to finish the "Errors and Exceptions" section of the tutorial.
try:
possibly_fail()
except ...:
handle_exception()
else:
no_exceptions()
finally:
always_run_this()

Python handling specific error codes?

Hey I'm wondering how to handle specific error codes. For example, [Errno 111] Connection refused
I want to catch this specific error in the socket module and print something.
If you want to get the error code, this seems to do the trick;
import errno
try:
socket_connection()
except socket.error as error:
if error.errno == errno.ECONNREFUSED:
print(os.strerror(error.errno))
else:
raise
You can look up errno error codes.
On Unix platforms, at least, you can do the following.
import socket, errno
try:
# Do something...
except socket.error as e:
if e.errno == errno.ECONNREFUSED:
# Handle the exception...
else:
raise
Before Python 2.6, use e.args[ 0 ] instead of e.errno.
This seems hard to do reliably/portably but perhaps something like:
import socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 4167))
except socket.error, e:
if 'Connection refused' in e:
print '*** Connection refused ***'
which yields:
$ python socketexception.py
*** Connection refused ***
Pretty yucky though.
I'm developing on Windows and found myself in the same predicament. But the error message always contains the error number. Using that information I just convert the exception to a string str(Exception), convert the error code I wanna check for to a string str(socket.errno.ERRORX) and check if the error code is in the exception.
Example for a connection reset exception:
except Exception as errorMessage:
if str(socket.errno.ECONNRESET) in str(errorMessage):
print("Connection reset")
#etc...
This avoids locale specific solutions but is still not platform independent unfortunately.

Python: except EOFError: ... doesn't work

I have a try/except block that sends a message and waits for confirmation from client. If the client terminates, pickle raises an EOFError, but the code below does not catch the error and execute the graceful shut down. It instead prints stack trace. I assume it has to do with the line "except socket.error, EOFError:" - am I using the wrong syntax to handle both socket.error and EOFError there?
try:
msgs = [1]
self.sock.send(pickle.dumps(msgs))
rdy = pickle.loads(self.sock.recv(2097152))
except socket.error, EOFError:
print 'log socketmanager closing'
self.terminate()
break
In Python 2.x, the form except a, b catches an exception of type a and assign it to a variable called b. In your case this would result in EOFError being ignored. Try this instead:
...
except (socket.error, EOFError):
...
Edit: to elaborate, the new syntax in Python 3.0, and available, though not required, in 2.6+, for capturing the value of an exception is except a as b.
break is causing the error, it can only be used inside a for loop or a try/finally block, not try/except, see docs and more.

How can I catch for a connection timeout error in Python's SMTPlib?

The error being thrown is:
error: [Errno 110] Connection timed out
I'm not sure what to except for?
try:
smtpObj = smtplib.SMTP('smtp.example.com')
smtpObj.starttls()
smtpObj.login('user','pass')
smtpObj.sendmail(sender, receivers, message)
print "Successfully sent email"
except smtplib.SMTPException('Error: unable to send email"'):
pass
except smtplib.socket.error ('Error: could not connect to server'):
pass
Thanks.
You need to provide the exception class, not an instance thereof. That is to say, the code should look like
try:
smtpObj = smtplib.SMTP('smtp.example.com')
smtpObj.starttls()
smtpObj.login('user','pass')
smtpObj.sendmail(sender, receivers, message)
print "Successfully sent email"
except smtplib.SMTPException: # Didn't make an instance.
pass
except smtplib.socket.error:
pass
The second exception, smtplib.socket.error, seems to be the applicable one to catch that error. It is usually accessed directly from the socket module import socket, socket.error.
Note that I said that was what the code "should" look like, and that's sort of an exaggeration. When using try/except, you want to include as little code as possible in the try block, especially when you are catching fairly general errors like socket.error.
I believe socket.error should work but if you post the code you're using, we can help you better. smtplib.SMTPConnectError should also be of interest.
Try something like this:
try:
server = smtplib.SMTP("something.com")
except (socket.error, smtplib.SMTPConnectError):
print >> stderr, "Error connecting"
sys.exit(-1)
OSError is the base class for smtplib.SMTPConnectError, socket.timeout, TimeoutError, etc. Therefore, you should catch OSError if you want to handle them all:
try:
...
except OSError:
...
See: https://bugs.python.org/issue20903

Categories

Resources