How do I write a decorator that restores the cwd?

How do I write a decorator that restores the current working directory to what it was before the decorated function was called? In other words, if I use the decorator on a function that does an os.chdir(), the cwd will not be changed after the function is called.


Asked by: Dexter580 | Posted: 01-10-2021






Answer 1

The answer for a decorator has been given; it works at the function definition stage as requested.

With Python 2.5+, you also have an option to do that at the function call stage using a context manager:

from __future__ import with_statement # needed for 2.5 ≤ Python < 2.6
import contextlib, os

@contextlib.contextmanager
def remember_cwd():
    curdir= os.getcwd()
    try: yield
    finally: os.chdir(curdir)

which can be used if needed at the function call time as:

print "getcwd before:", os.getcwd()
with remember_cwd():
    walk_around_the_filesystem()
print "getcwd after:", os.getcwd()

It's a nice option to have.

EDIT: I added error handling as suggested by codeape. Since my answer has been voted up, it's fair to offer a complete answer, all other issues aside.

Answered by: Chloe740 | Posted: 02-11-2021



Answer 2

The path.py module (which you really should use if dealing with paths in python scripts) has a context manager:

subdir = d / 'subdir' #subdir is a path object, in the path.py module
with subdir:
  # here current dir is subdir

#not anymore

(credits goes to this blog post from Roberto Alsina)

Answered by: Sarah123 | Posted: 02-11-2021



Answer 3

The given answers fail to take into account that the wrapped function may raise an exception. In that case, the directory will never be restored. The code below adds exception handling to the previous answers.

as a decorator:

def preserve_cwd(function):
    @functools.wraps(function)
    def decorator(*args, **kwargs):
        cwd = os.getcwd()
        try:
            return function(*args, **kwargs)
        finally:
            os.chdir(cwd)
    return decorator

and as a context manager:

@contextlib.contextmanager
def remember_cwd():
    curdir = os.getcwd()
    try:
        yield
    finally:
        os.chdir(curdir)

Answered by: Kellan198 | Posted: 02-11-2021



Answer 4

You dont need to write it for you. With python 3.11, the developers have written it for you. Checkout their code at github.com/python/cpython. Its in module contextlib.

import contextlib
with contextlib.chdir('/path/to/cwd/to'):
    pass

Answered by: Tess265 | Posted: 02-11-2021



Answer 5

def preserve_cwd(function):
   def decorator(*args, **kwargs):
      cwd = os.getcwd()
      result = function(*args, **kwargs)
      os.chdir(cwd)
      return result
   return decorator

Here's how it's used:

@preserve_cwd
def test():
  print 'was:',os.getcwd()
  os.chdir('/')
  print 'now:',os.getcwd()

>>> print os.getcwd()
/Users/dspitzer
>>> test()
was: /Users/dspitzer
now: /
>>> print os.getcwd()
/Users/dspitzer

Answered by: Caroline641 | Posted: 02-11-2021



Similar questions

python - How do I write a async decorator that restores the cwd?

I am trying to create a decorator for an async function that restores cwd. I am using this as a reference: How do I write a decorator that restores the cwd? This is what I came up with. It's not preserving the cwd, any pointers? import os import asyncio ...


python - How do I write a async decorator that restores the cwd?

I am trying to create a decorator for an async function that restores cwd. I am using this as a reference: How do I write a decorator that restores the cwd? This is what I came up with. It's not preserving the cwd, any pointers? import os import asyncio ...


Writing a TTL decorator in Python

I'm trying to write a TTL decorator in python. Basically I give it raise an exception if the function doesn't answer in the selected time. You can find the thead2 snippets on http://sebulba.wikispaces.com/recipe+thread2 from thread2 import Thread """ A TTL decorator. """ class Worker(Thread): def __init__(self...


decorator - In Python, is it possible to access the class which contains a method, given only a method object?

I'm pretty new to Python, and haven't been able to find an answer to this question from searching online. Here is an example decorator that does nothing (yet) def my_decorator(text): def wrap(f): # grab magic f.parent_class_object.my_var and append text def wrap_f(*args, **kwargs): f(*args, **kwargs) return wrap_f return wrap Here is an example class


python - A simple freeze behavior decorator

I'm trying to write a freeze decorator for Python. The idea is as follows : (In response to the two comments) I might be wrong but I think there is two main use of test case. One is the test-driven development : Ideally , developers are writing case before writing the code. It usually helps defining the architecture because this discipline forces to define the rea...


python - How to return a function value with decorator and thread

have this code import threading def Thread(f): def decorator(*args,**kargs): print(args) thread = threading.Thread(target=f, args=args) thread.start() thread.join() decorator.__name__ = f.__name__ return decorator @Thread def add_item(a, b): return a+b print(add_item(2,2)) but the function never return the value, exits a way to get ...


decorator - Python convert args to kwargs

I am writing a decorator that needs to call other functions prior to call of the function that it is decorating. The decorated function may have positional arguments, but the functions the decorator will call can only accept keyword arguments. Does anyone have a handy way of converting positional arguments into keyword arguments? I know that I can get a list of the variable names of the decorated function:


Python Decorator 3.0 and arguments to the decorator

I'm excited to see the latest version of the decorator python module (3.0). It looks a lot cleaner (e.g. the syntax is more sugary than ever) than previous iterations. However, it seems to have lousy support (e.g. "sour" syntax, to horribly stretch the metaphor) for decorators that take arguments themselves. Does anyone have a good example for how you'd cleanly do this using decorator 3....


python - Decorator to mark a method to be executed no more than once even if called several times

I will go straight to the example: class Foo: @execonce def initialize(self): print 'Called' &gt;&gt;&gt; f1 = Foo() &gt;&gt;&gt; f1.initialize() Called &gt;&gt;&gt; f1.initialize() &gt;&gt;&gt; f2 = Foo() &gt;&gt;&gt; f2.initialize() Called &gt;&gt;&gt; f2.initialize() &gt;&gt;&gt; I tried to define execonce but could not write one that works with methods. P...


python - Creating a decorator in a class with access to the (current) class itself

Currently, I'm doing it in this fashion: class Spam(object): decorated = None @classmethod def decorate(cls, funct): if cls.decorated is None: cls.decorated = [] cls.decorated.append(funct) return funct class Eggs(Spam): pass @Eggs.decorate def foo(): print "spam and eggs" print Eggs.decorated # [&lt;function foo at 0x...&gt;] print Spam.decora...


decorator - Python decorate a class to change parent object type

Suppose you have two classes X &amp; Y. You want to decorate those classes by adding attributes to the class to produce new classes X1 and Y1. For example: class X1(X): new_attribute = 'something' class Y1(Y): new_attribute = 'something' new_attribute will always be the same for both X1 and Y1. X &amp; Y are not related in any meaningful way, except that multiple inhe...


How can I use a class instance variable as an argument for a method decorator in Python?

How can I use a class instance variable as an argument for a method decorator in Python? The following is a minimal example shows what I'm trying to do. It obviously fails as the decorator function does not have access to the reference to the instance and I have no idea how to get access to the reference from the decorator. def decorator1(arg1): def wrapper(function): print "decorator argument: ...






Still can't find your answer? Check out these communities...



PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python



top