getting with statement to deal with various exceptions

M

mk

Hello,

I'm trying to learn how with statement can be used to avoid writing:

prepare()
try:
something_that_can_raise_SomeException()
except SomeException, err:
deal_with_SomeException
finally:
tear_it_down()

Verbose, not very readable. OK, "with" to the rescue?

Let's take a textbook example from PEP:

with open('/etc/passwd', 'r') as f:
BLOCK

Well, great, it's neat that "with" closes the file after BLOCK has
finished execution, but what if the file isn't there and attempt to open
it raises IOException? I'd like to be able to catch it precisely to
avoid writing verbose try: .. except: .. finally: .. blocks which as I
understand has been much of the rationale behind creating "with"
statement in the first place.

"with" statement only allows easy dealing with prepare() and
tear_it_down(). When I try to get it to deal with exceptions that might
happen, it becomes more complicated:

class FileContextManager:
def __enter__(self, filename, mode):
f = open(filename, mode)
return f
def __exit__(self, etype, evalue, etraceback):
print "etype", etype, "evalue", evalue, "etraceback", etraceback

a = f.readlines()



Traceback (most recent call last):
File "<pyshell#36>", line 1, in <module>
with FileContextManager("somefile", "r") as f:
TypeError: this constructor takes no arguments


Bummer.

Plus, no documentation I've read (on effbot, in PEP 343, etc) says how
to deal with the exception happening in __enter__ method of context
manager, which is precisely what I'd like to do.

This is only natural, isn't it? When e.g. reading the file, preparation
phase is typically checking if it can be opened in the first place. So
it falls into __enter__ method of context manager.

"with" limited only to successful execution of a_statement from "with
a_statement" seems like limited benefit to me.

I'd like to be able to write smth like

class FileContextManager:
def __enter__(self, filename, mode):
f = open(filename, mode)
return f
def __except__(IOError, err):
do_this
print err
def __except__(RuntimeError, err):
do_that
print "something bad happened", err
def __exit__(self, etype, evalue, etraceback):
print "etype", etype, "evalue", evalue, "etraceback", etraceback

__exit__ deals with exceptions happening in the BLOCK below "with"
statement, not with exceptions raised in "a_statement", when executing

with a_statement as var:
BLOCK

In the above way "with" would give me the benefit of more terse, but
still understandable and efficient code.

Well, I can always do this:

try:
with open("somefile.txt") as txtfile:
for line in txtfile:
print line
except IOError:
print "No such file."


No such file.


But that's just ugly, nested too many times (flat is better than nested,
right?) and not all that more readable.
 
M

mk

from __future__ import with_statement

class ExceptionManager(object):
def __enter__(self):
pass
def __exit__(self,exc_type,exc_value,tb):
if exc_type == IOError:
print 'IOError',exc_value[1]
return True # suppress it

with ExceptionManager():
with open('test.txt') as f:
f.read()

Neat. I think I'm going to use this approach, since BDFL-in-chief is
unlikely to listen to me in any foreseeable future. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top