2

here is what I am basically trying to do:

import sh, os

with sh.cd('/tmp'):
  print os.getcwd()

print os.getcwd()

I get the following error though

line 3, in <module>
    with sh.cd('/tmp'):
AttributeError: __exit__

What am I missing here? Are there alternative solutions to change directory within a context?

Igor Lankin
  • 1,416
  • 2
  • 14
  • 30
  • 1
    There's a good solution in [this answer](http://stackoverflow.com/a/13197763/1901786). – whereswalden Jun 28 '14 at 18:07
  • thx, @whereswalden. I have done some research before, and stumbled over that answer as well. But I wonder whether there is no "short" solution. This seems like a frequent use-case. – Igor Lankin Jun 28 '14 at 18:10

2 Answers2

6

You can't use just any class/function as a context manager, it has to actually explicitly be implemented that way, using either the contextlib.contextmanager decorator on a function, or in the case of a class, by defining the __enter__ and __exit__ instance methods.

The sh.cd function you're using is simply a wrapper around os.chdir:

>>> import sh
>>> sh.cd
<bound method Environment.b_cd of {}>

b_cd is defined as:

def b_cd(self, path):
    os.chdir(path)

As you can see, it's just a normal function; it can't be used as a context manager.

The link whereswalden provided shows a good way of implementing the behavior you want as a class. It could similarly be implemented as a function like this:

import contextlib
import os

@contextlib.contextmanager
def cd(path):
   old_path = os.getcwd()
   os.chdir(path)
   try:
       yield
   finally:
       os.chdir(old_path)

Sample usage:

print(os.getcwd())
with cd("/"):
    print os.getcwd()
print(os.getcwd())

Output:

'/home/dan'
'/'
'/home/dan'
dano
  • 91,354
  • 19
  • 222
  • 219
2

sh now has the pushd() function that can be used as a context manager to change the current directory temporarily:

import sh

with sh.pushd("/tmp"):
    sh.touch("a_file")

See https://amoffat.github.io/sh/sections/command_class.html?highlight=pushd#pushd

Erik Cederstrand
  • 9,643
  • 8
  • 39
  • 63