Unestablished connection and content manager - python

The following function allows to use the with-statment and the a pop connection. But if the connection is not established, the quit() in finally will raise an exception. How can this be fixed?
#contextmanager
def pop_connect(server, user, password, timeout, use_SSL=False):
try:
pop = poplib.POP3_SSL if use_SSL else poplib.POP3
pop_conn = pop(server, timeout=timeout)
pop_conn.pass_(password)
yield pop_conn
except poplib.error_proto as pop_error:
print('Authentication for receiving emails failed:{}'.format(pop_error))
except OSError as os_error:
print('Name resolution or connection failed:{}'.format(os_error))
finally:
pop_conn.quit()

I suppose you can put your pop_conn.quit() in a try: with pass as corresponding except action:
finally:
try:
pop_conn.quit()
except <WhaterverException>:
pass

The solution is to rethrow the exceptions in the handlers. The contextmanager than does not except the yield:
#contextmanager
def pop_connect(server, user, password, timeout, use_SSL=False):
try:
pop_conn = poplib.POP3_SSL(server,timeout=timeout) if use_SSL else poplib.POP3_SSL(server,timeout=timeout)
pop_conn.user(user)
pop_conn.pass_(password)
yield pop_conn
except poplib.error_proto as pop_error:
print('Receiving mail failed:{}'.format(pop_error))
raise
except OSError as os_error:
print('Name resolution or connection failed:{}'.format(os_error))
raise
finally:
try:
pop_conn.quit()
except UnboundLocalError:
pass

Related

Can't catch connection error clickhouse-driver db api

I'm trying to catch a connection error when connecting to kx using the clickhouse-driver db api in python. But for some reason, the try: block passes without errors, and I don't get exception
def __enter__(self):
try:
self.connector = db.connect(dsn=self.connection_string)
except Error as e: # pass
self.error = str(e)[:250]
self.connector = None
return self
And the error only happens when execute sql is executed. Is there any way to get a connection error at the moment of connection?
I added execute('select 1'). Because only after execute we are creating instance of class, so after that I can get connection exception.
def __enter__(self):
try:
self.connector = dbp.connect(dsn=self.connection_string)
self.cur = self.connector.cursor()
self.cur.execute('select 1')
except dbp.Error as e:
self.error = '\nConnection error occurred: ' + '\n' + str(e)[:250]
self.connector = None
return self

How to return SerialException error message, Object Serial?

How to return Error message that output by SerialException? In here i try to open port in port that already open. I want to get error that occurs. In the case SerialException will return Access is denied
could not open port 'COM38': PermissionError(13, 'Access is denied.',
None, 5)
import serial
from serial import SerialException
def open:
try:
serial.Serial('COM38', 9600)
return True
except SerialException:
#How to return error message that serial exception occurs?
return Raise
print(open())
Hope help.
import serial
from serial import SerialException
def open:
try:
serial.Serial('COM38', 9600)
return True
except PermissionError as e:
message = str(e)
raise SerialException(message)
except SerialException as ex:
print(ex)
print(open())

Handling exception (when no connection) in pyodbc

I'm trying to catch the exception when connecting to database and have no connection, but I always freeze at pyodbc.connect(connstr). I tried all errors from documentation, tried just "except Exception" but I see my program just freeze when cannot connect to database and don't check except section. (Freeze is caused by my on-purpose disconnection from database and program just does nothing (windows "no answer") until my hard reset):
import pyodbc
connstr=('DRIVER={SQL Server Native Client 11.0};Server="server_ip";port=1433;Network Library=DBMSSOCN;Database="name";uid="uid";pwd="pwd";')
try:
print("I'm here - no problem")
conn=pyodbc.connect(connstr)
print("of course not here")
except ...no_matter_what_I_write_here... :
print("but never there too")
It was too simple (thank You Pynchia for Your suggestion):
try:
conn=pyodbc.connect(connstr, timeout=5)
except pyodbc.Error as err:
print("Couldn't connect")
Assuming you are not connecting on thread. Coz Signals will not work in non main thread.
import signal
from contextlib import contextmanager
class TimeoutError(Exception): pass
#contextmanager
def time_limit(seconds):
def signal_handler(signum, frame):
raise TimeoutError("Time out")
signal.signal(signal.SIGALRM, signal_handler)
signal.alarm(seconds)
try:
yield
finally:
signal.alarm(0)
try:
with time_limit(10):
conn=pyodbc.connect(connstr)
except TimeoutError as e:
print "couldn't connect for long time"

Python: how to distinguish between socket error and timeout?

I'm having the following code:
try:
while 1:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.settimeout(5);
s.connect((HOST,PORT))
print("before send")
#time.sleep(10);
#s.sendall('GET / HTTP/1.1\r\nConnection: Keep-Alive\r\nHost: www.google.lt\r\n\r\n')
data=s.recv(52)
print("after send");
s.close()
if string.find(data,"HTTP/1.1 200 OK") == -1:
print("Lost Connection")
print(data)
time.sleep(2)
except KeyboardInterrupt:
print("CTRL C occured")
except socket.error:
print("socket error occured: ")
except socket.timeout:
print("timeout error")
I have commented the sendall function to test how recv generates timeout exception.
But the problem is that i get socket.error exception.
If i change the last lines of code to:
except socket.timeout:
print("timeout error")
except socket.error:
print("socket error occured: ")
Then i get socket.timeout exception.
So what exception is really generated?
socket.timeout is a subclass of socket.error. Really it's socket.timeout. When you catch a socket.error first, you catch a more general case.
>>> issubclass(socket.timeout, socket.error)
True
This code is correct:
except socket.timeout:
print("timeout error")
except socket.error:
print("socket error occured: ")
Try to catch specifically socket.timeout, then other socket.errors.

Correct way of handling exceptions in Python?

I have searched for other posts, as I felt this is a rather common problem, but all other Python exception questions I have found didn't reflect my problem.
I will try to be as specific here as I can, so I will give a direct example. And pleeeeease do not post any workarounds for this specific problem. I am not specifically interested how you can send an email much nicer with xyz.
I want to know how you generally deal with dependent, error prone statements.
My question is, how to handle exceptions nicely, ones that depend on one another, meaning:
Only if the first step was successful, try the next, and so on. One more criterion is: All exceptions have to be caught, this code has to be robust.
For your consideration, an example:
try:
server = smtplib.SMTP(host) #can throw an exception
except smtplib.socket.gaierror:
#actually it can throw a lot more, this is just an example
pass
else: #only if no exception was thrown we may continue
try:
server.login(username, password)
except SMTPAuthenticationError:
pass # do some stuff here
finally:
#we can only run this when the first try...except was successful
#else this throws an exception itself!
server.quit()
else:
try:
# this is already the 3rd nested try...except
# for such a simple procedure! horrible
server.sendmail(addr, [to], msg.as_string())
return True
except Exception:
return False
finally:
server.quit()
return False
This looks extremely unpythonic to me, and the error handling code is triple the real business code, but on the other hand how can I handle several statements that are dependent on one another, meaning statement1 is prerequisite for statement2 and so on?
I am also interested in proper resource cleanup, even Python can manage that for itself.
Thanks, Tom
Instead of using the try/except's else block, you could simply return when it errors:
def send_message(addr, to, msg):
## Connect to host
try:
server = smtplib.SMTP(host) #can throw an exception
except smtplib.socket.gaierror:
return False
## Login
try:
server.login(username, password)
except SMTPAuthenticationError:
server.quit()
return False
## Send message
try:
server.sendmail(addr, [to], msg.as_string())
return True
except Exception: # try to avoid catching Exception unless you have too
return False
finally:
server.quit()
That's perfectly readable and Pythonic..
Another way of doing this is, rather than worry about the specific implementation, decide how you want your code to look, for example..
sender = MyMailer("username", "password") # the except SocketError/AuthError could go here
try:
sender.message("addr..", ["to.."], "message...")
except SocketError:
print "Couldn't connect to server"
except AuthError:
print "Invalid username and/or password!"
else:
print "Message sent!"
Then write the code for the message() method, catching any errors you expect, and raising your own custom one, and handle that where it's relevant. Your class may look something like..
class ConnectionError(Exception): pass
class AuthError(Exception): pass
class SendError(Exception): pass
class MyMailer:
def __init__(self, host, username, password):
self.host = host
self.username = username
self.password = password
def connect(self):
try:
self.server = smtp.SMTP(self.host)
except smtplib.socket.gaierror:
raise ConnectionError("Error connecting to %s" % (self.host))
def auth(self):
try:
self.server.login(self.username, self.password)
except SMTPAuthenticationError:
raise AuthError("Invalid username (%s) and/or password" % (self.username))
def message(self, addr, to, msg):
try:
server.sendmail(addr, [to], msg.as_string())
except smtplib.something.senderror, errormsg:
raise SendError("Couldn't send message: %s" % (errormsg))
except smtp.socket.timeout:
raise ConnectionError("Socket error while sending message")
In general, you want to use as few try blocks as possible, distinguishing failure conditions by the kinds of exceptions they throw. For instance, here's my refactoring of the code you posted:
try:
server = smtplib.SMTP(host)
server.login(username, password) # Only runs if the previous line didn't throw
server.sendmail(addr, [to], msg.as_string())
return True
except smtplib.socket.gaierror:
pass # Couldn't contact the host
except SMTPAuthenticationError:
pass # Login failed
except SomeSendMailError:
pass # Couldn't send mail
finally:
if server:
server.quit()
return False
Here, we use the fact that smtplib.SMTP(), server.login(), and server.sendmail() all throw different exceptions to flatten the tree of try-catch blocks. In the finally block we test server explicitly to avoid invoking quit() on the nil object.
We could also use three sequential try-catch blocks, returning False in the exception conditions, if there are overlapping exception cases that need to be handled separately:
try:
server = smtplib.SMTP(host)
except smtplib.socket.gaierror:
return False # Couldn't contact the host
try:
server.login(username, password)
except SMTPAuthenticationError:
server.quit()
return False # Login failed
try:
server.sendmail(addr, [to], msg.as_string())
except SomeSendMailError:
server.quit()
return False # Couldn't send mail
return True
This isn't quite as nice, as you have to kill the server in more than one place, but now we can handle specific exception types different ways in different places without maintaining any extra state.
If it was me I would probably do something like the following:
try:
server = smtplib.SMTP(host)
try:
server.login(username, password)
server.sendmail(addr, [to], str(msg))
finally:
server.quit()
except:
debug("sendmail", traceback.format_exc().splitlines()[-1])
return True
All errors are caught and debugged, the return value == True on success, and the server connection is properly cleaned up if the initial connection is made.
Just using one try-block is the way to go. This is exactly what they
are designed for: only execute the next statement if the previous
statement did not throw an exception. As for the resource clean-ups,
maybe you can check the resource if it needs to be cleaned up
(e.g. myfile.is_open(), ...) This does add some extra conditions, but
they will only be executed in the exceptional case. To handle the case
that the same Exception can be raised for different reasons, you
should be able to retrieve the reason from the Exception.
I suggest code like this:
server = None
try:
server = smtplib.SMTP(host) #can throw an exception
server.login(username, password)
server.sendmail(addr, [to], msg.as_string())
server.quit()
return True
except smtplib.socket.gaierror:
pass # do some stuff here
except SMTPAuthenticationError:
pass # do some stuff here
except Exception, msg:
# Exception can have several reasons
if msg=='xxx':
pass # do some stuff here
elif:
pass # do some other stuff here
if server:
server.quit()
return False
It is no uncommon, that error handling code exceeds business code. Correct error handling can be complex.
But to increase maintainability it helps to separate the business code from the error handling code.
I would try something like this:
class Mailer():
def send_message(self):
exception = None
for method in [self.connect,
self.authenticate,
self.send,
self.quit]:
try:
if not method(): break
except Exception, ex:
exception = ex
break
if method == quit and exception == None:
return True
if exception:
self.handle_exception(method, exception)
else:
self.handle_failure(method)
def connect(self):
return True
def authenticate(self):
return True
def send(self):
return True
def quit(self):
return True
def handle_exception(self, method, exception):
print "{name} ({msg}) in {method}.".format(
name=exception.__class__.__name__,
msg=exception,
method=method.__name__)
def handle_failure(self, method):
print "Failure in {0}.".format(method.__name__)
All of the methods (including send_message, really) follow the same protocol: they return True if they succeeded, and unless they actually handle an exception, they don't trap it. This protocol also makes it possible to handle the case where a method needs to indicate that it failed without raising an exception. (If the only way your methods fail is by raising an exception, that simplifies the protocol. If you're having to deal with a lot of non-exception failure states outside of the method that failed, you probably have a design problem that you haven't worked out yet.)
The downside of this approach is that all of the methods have to use the same arguments. I've opted for none, with the expectation that the methods I've stubbed out will end up manipulating class members.
The upside of this approach is considerable, though. First, you can add dozens of methods to the process without send_message getting any more complex.
You can also go crazy and do something like this:
def handle_exception(self, method, exception):
custom_handler_name = "handle_{0}_in_{1}".format(\
exception.__class__.__name__,
method.__name__)
try:
custom_handler = self.__dict__[custom_handler_name]
except KeyError:
print "{name} ({msg}) in {method}.".format(
name=exception.__class__.__name__,
msg=exception,
method=method.__name__)
return
custom_handler()
def handle_AuthenticationError_in_authenticate(self):
print "Your login credentials are questionable."
...though at that point, I might say to myself, "self, you're working the Command pattern pretty hard without creating a Command class. Maybe now is the time."
Why not one big try: block? This way, if any exception is caught, you'll go all the way to the except. And as long as all the exceptions for the different steps are different, you can always tell which part it was that fired the exception.
I like David's answer but if you are stuck on the server exceptions you can also check for server if is None or states. I flattened out the method a bit bit it is still a but unpythonic looking but more readable in the logic at the bottom.
server = None
def server_obtained(host):
try:
server = smtplib.SMTP(host) #can throw an exception
return True
except smtplib.socket.gaierror:
#actually it can throw a lot more, this is just an example
return False
def server_login(username, password):
loggedin = False
try:
server.login(username, password)
loggedin = True
except SMTPAuthenticationError:
pass # do some stuff here
finally:
#we can only run this when the first try...except was successful
#else this throws an exception itself!
if(server is not None):
server.quit()
return loggedin
def send_mail(addr, to, msg):
sent = False
try:
server.sendmail(addr, to, msg)
sent = True
except Exception:
return False
finally:
server.quit()
return sent
def do_msg_send():
if(server_obtained(host)):
if(server_login(username, password)):
if(send_mail(addr, [to], msg.as_string())):
return True
return False

Categories