So, yesterday's article on
with turned out the be a bit wrong. As lesson in reading the
explanatory text and not just the example code. (Or possibly a lesson
in providing better example code!).
So, I gave an example along the lines of:
@contextmanager
def chdir(path):
# This code is wrong. Don't use it!
cwd = os.getcwd()
os.chdir(path)
yield
os.chdir(cwd)
Now, this appears to mostly work. The problem occurs when you have some code like:
with chdir('/'):
raise Exception()
In this case the final cleanup code (
os.chdir(cwd)
)will not be executed, which is almost certainly not what you want.
The correct was to write this is:
@contextmanager
def chdir(path):
cwd = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(cwd)
Writing it this way the final
os.chdir(cwd)
will be executed,and the exception will still be propagated. So I think this kind of sucks, because
I'd really have preferred it to have this behaviour by default. To this end
I've created a
simplecontextmanager
function decorator. Basically youcan use it like so:
@simplecontextmanager
def chdir(path):
cwd = os.getcwd()
os.chdir(path)
yield
os.chdir(cwd)
Looks pretty much like the first example, however it will have the semantics of
the second example. Now clearly the
simplecontextmanager
doesn't providethe whole range of flexibility that
contextmanager
does, but for simplecode it is more straightforward.
My pyutil git repo has been
updated to have working version of the
chdir
, umask
andupdate_env
context managers, and also contains the source for thenew
simplecontextmanager
.Moral of the story, test your code and read the docs carefully!
DIGITAL JUICE
No comments:
Post a Comment
Thank's!