71

What is the intended way to change directory using the Python pathlib (Documentation) functionality?

Lets assume I create a Path object as follows:

from pathlib import Path
path = Path('/etc')

Currently I just know the following, but that seems to undermine the idea of pathlib.

import os
os.chdir(str(path))
Lukas
  • 2,330
  • 2
  • 22
  • 31
  • changing the current directory is rarely a good idea anyway. Why do you need to change directory for? – Jean-François Fabre Jan 19 '17 at 12:58
  • There is a small bash script I want to rewrite in Python. That way I can handle errors more easily than calling an external bash script. – Lukas Jan 19 '17 at 13:41
  • 1
    you don't have to use `pathlib` if you don't need it - `os.chdir('/etc')` – furas Jan 19 '17 at 14:48
  • I feel like `pathlib` leads to more elegant code. But since `cd` is not elegant by any means, I might as well go with `os.chdir('/etc')`? – Lukas Jan 19 '17 at 14:54
  • `pathlib` is module to work with paths, not to change directory. – furas Jan 19 '17 at 14:56
  • 3
    @furas; tell that to the core devs. See Path.read_bytes and Path.read_text. – Jürgen A. Erhard Jul 30 '21 at 19:11
  • Since `pathlib` doesn't offer functionality specifically for this, the question reduces to "how do I change directories?", where the `Path` instance simply *specifies* the directory (and tools like `os.chdir` already work with that specification). So this is a duplicate - and would really remain a duplicate if the functionality were added later, *because that would be a legitimate answer for the canonical too*. – Karl Knechtel Mar 15 '23 at 05:43

3 Answers3

60

Based on the comments I realized that pathlib does not help changing directories and that directory changes should be avoided if possible.

Since I needed to call bash scripts outside of Python from the correct directory, I opted for using a context manager for a cleaner way of changing directories similar to this answer:

import os
import contextlib
from pathlib import Path

@contextlib.contextmanager
def working_directory(path):
    """Changes working directory and returns to previous on exit."""
    prev_cwd = Path.cwd()
    os.chdir(path)
    try:
        yield
    finally:
        os.chdir(prev_cwd)

A good alternative is to use the cwd parameter of the subprocess.Popen class as in this answer.

If you are using Python <3.6 and path is actually a pathlib.Path, you need str(path) in the chdir statements.

Lukas
  • 2,330
  • 2
  • 22
  • 31
  • 2
    This is exactly what I needed! I'm testing a command line tool whose required parameters depend on the cwd, so I need to move the cwd around in order to test this functionality. However if I write it the naive way, then when a test fails it will throw an unexpected exception and the cwd doesn't get moved back, meaning that all future tests start with the wrong cwd and give useless errors. Using a context manager means I *know* it gets moved back! I think try-except-finally blocks are also valid, but writing a context manager is more reliable and saves code over multiple tests. – William May 23 '20 at 16:28
25

In the Python 3.6 or above, os.chdir() can deal with Path object directly. In fact, the Path object can replace most str paths in standard libraries.

os.chdir(path) Change the current working directory to path.

This function can support specifying a file descriptor. The descriptor must refer to an opened directory, not an open file.

New in version 3.3: Added support for specifying path as a file descriptor on some platforms.

Changed in version 3.6: Accepts a path-like object.

import os
from pathlib import Path

path = Path('/etc')
os.chdir(path)

This may help in the future projects which do not have to be compatible with 3.5 or below.

Yan QiDong
  • 3,696
  • 1
  • 24
  • 25
  • Yes, that is very nice indeed. I hope the Python community either accepts `pathlib.Path` anywhere or abandons it altogether. – Lukas Mar 01 '18 at 12:24
  • @Lukas: I really want to like it, but currently I can't accept it. And since it's been three years since your comment, I suspect I can't ever… and os.path will stay anyway. I could and would accept it if it could replace os.path completely. Therein lies the rub. For me at least. – Jürgen A. Erhard Jul 30 '21 at 19:14
  • Naturally, **this should be the accepted answer.** Yes, it'd be preferable for API orthogonality if a hypothetical full-fledged `pathlib.Path.chdir()` method existed – but this is the next best thing. Let's not let the perfect become the enemy of the good *yet again.* – Cecil Curry Nov 05 '21 at 05:23
2

If you don't mind using a third-party library:

$ pip install path

then:

from path import Path

with Path("somewhere"):
    # current working directory is now `somewhere`
    ...
# current working directory is restored to its original value. 

or if you want to do it without the context manager:

Path("somewhere").cd()
# current working directory is now changed to `somewhere`
AXO
  • 8,198
  • 6
  • 62
  • 63
  • 18
    Just to be perfectly clear, this is not the standard library pathlib. Using with pathlib.Path('x') does not change directory. – Jeremy Woodland Apr 09 '21 at 01:30