[Python-ideas] chdir context manager

Terry Reedy tjreedy at udel.edu
Sat Jan 19 14:37:17 CET 2013


On 1/19/2013 5:10 AM, Daniel Shahaf wrote:
> The following is a common pattern (used by, for example,
> shutil.make_archive):
>
>      save_cwd = os.getcwd()
>      try:
>          foo()
>      finally:
>          os.chdir(save_cwd)
>
> I suggest this deserves a context manager:
>
>      with saved_cwd():
>          foo()

This strikes me as not a proper context manager. A context manager 
should create a temporary, altered context. One way is to add something 
that is deleted on exit. File as context managers are the typical 
example. Another way is to alter something after saving the restore 
info, and restoring on exit. An example would be a context manager to 
temporarily change stdout. (Do we have one? If not, it would be at least 
as generally useful as this proposal.)

So to me, your proposal is only 1/2 or 2/3 of a context manager. (And 
'returns an open file descriptor for the saved directory' seems backward 
or wrong for a context manager.) It does not actually make a new 
context. A proper temp_cwd context manager should have one parameter, 
the new working directory, with chdir(new_cwd) in the enter method. To 
allow for conditional switching, the two chdir system calls could be 
conditional on new_cwd (either None or '' would mean no chdir calls).

Looking at your pattern, if foo() does not change cwd, the save and 
restore is pointless, even if harmless. If foo does change cwd, it 
should also restore it, whether explicitly or with a context manager 
temp_cwd.

Looking at your actual example, shutil.make_archive, the change and 
restore are conditional and asymmetrical.

   save_cwd = os.getcwd()
   if root_dir is not None:
     ...
     if not dry_run:
       os.chdir(root_dir)
   ...
   finally:
     if root_dir is not None:
     ...
       os.chdir(save_cwd)

The initial chdir is conditional on dry_run (undocumented, but passed on 
to the archive function), the restore is not. Since I believe not 
switching on dry_runs is just a minor optimization, I believe that that 
condition could be dropped and the code re-written as

   with new_cwd(root_dir):
     ...

I am aware that this would require a change in the finally logging, but 
that would be true of the original proposal also.

-- 
Terry Jan Reedy




More information about the Python-ideas mailing list