Search code examples
pythonshellcontextmanager

sh.cd using context manager


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?


Solution

  • 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'