169

Ok...I dont know where module x is, but I know that I need to get the path to the directory two levels up.

So, is there a more elegant way to do:

import os
two_up = os.path.dirname(os.path.dirname(__file__))

Solutions for both Python 2 and 3 are welcome!

Shubham
2,8655 gold badges27 silver badges38 bronze badges
asked Jan 8, 2015 at 15:49
3
  • 2
    I think your solution is perfectly fine. A pathlib solution is a little nicer and more readable, but isn't included with Python 2.7. I'd say stick with what you've got, maybe add a comment. Commented Jan 8, 2015 at 17:02
  • Perhaps worth adding the pip install pathlib2 option to maintain sanity in 2.7. Commented Mar 19, 2018 at 9:11
  • In case you want to get the directory two levels up of your current working directory you can perfectly use: os.path.abspath(os.path.join(os.getcwd(), os.path.pardir, os.path.pardir)) Commented May 3, 2022 at 12:29

18 Answers 18

226

You can use pathlib. Unfortunately this is only available in the stdlib for Python 3.4. If you have an older version you'll have to install a copy from PyPI here. This should be easy to do using pip.

from pathlib import Path
p = Path(__file__).parents[1]
print(p)
# /absolute/path/to/two/levels/up

This uses the parents sequence which provides access to the parent directories and chooses the 2nd one up.

Note that p in this case will be some form of Path object, with their own methods. If you need the paths as string then you can call str on them.

answered Jan 8, 2015 at 15:56
Sign up to request clarification or add additional context in comments.

10 Comments

Thats a nice answer thanks and great for py3. For py2 it is possible not any better than my initial attempt as it creates and extra dependency
This should not be the accepted answer as the Path class's parents is dependent upon the execution location. If you execute your __file__ from its current directory the Path class will have no parents. Either @Sebi2020's answer should be accepted, or your original method should be used. I believe your original method is more readable.
You may need to do p = Path(os.path.abspath(__file__)).parents[1]
@AdamRaudonis Instead of os.path.abspath, you can also use Path(__file__).resolve().parents[1]
As @Kazanz mentioned, this solution doesn't work when executing from other paths. The best solution is: p = Path(__file__).resolve().parents[1]. I also added it as an answer.
|
84

Very easy:

Here is what you want:

import os.path as path
two_up = path.abspath(path.join(__file__ ,"../.."))
answered Jan 8, 2015 at 16:11

10 Comments

And perhaps use os.pardir rather than ...
does sys.argv[0] not return module that was run by python.exe? So this wouldn't necessary work if the module im interested in was imported from some other package..am I right here?
If you want to use it in a module instead use __file__.
@jme do you know an OS where you get the parent directory with another string than".."???
@Sebi2020 Yep, notably the old Mac OS. Here's a list: en.wikipedia.org/wiki/Path_(computing)
|
34

I was going to add this just to be silly, but also because it shows newcomers the potential usefulness of aliasing functions and/or imports.

Having written it, I think this code is more readable (i.e. lower time to grasp intention) than the other answers to date, and readability is (usually) king.

from os.path import dirname as up
two_up = up(up(__file__))

Note: you only want to do this kind of thing if your module is very small, or contextually cohesive.

answered Jun 24, 2017 at 3:35

Comments

32

The best solution (for python>= 3.4) when executing from any directory is:

from pathlib import Path
two_up = Path(__file__).resolve().parents[1]
answered Nov 6, 2018 at 9:48

Comments

11

For getting the directory 2 levels up:

 import os.path as path
 curr_dir=Path(os.path.dirname(os.path.abspath(__file__)))
 two_dir_up_=os.fspath(Path(curr_dir.parent.parent).resolve())

I have done the following to go up two and drill down on other dir

 default_config_dir=os.fspath(Path(curr_dir.parent.parent,
 'data/config').resolve()) 
answered May 31, 2017 at 18:01

2 Comments

Location of file and your cwd don't have to be the same. Thus your solution does not always produce the same result.
Gives the path relative to the working directory not module
5

Personally, I find that using the os module is the easiest method as outlined below. If you are only going up one level, replace ('../..') with ('..').

 import os
 os.chdir('../..')
--Check:
 os.getcwd()
answered Jun 29, 2015 at 19:47

2 Comments

Is it acceptable to hardcode the '/' I would have expected to read os.chdir(os.join('..', '..'))
Gives the path relative to the working directory not module
4

More cross-platform implementation will be:

import pathlib
two_up = (pathlib.Path(__file__) / ".." / "..").resolve()

Using parent is not supported on Windows. Also need to add .resolve(), to:

Make the path absolute, resolving all symlinks on the way and also normalizing it (for example turning slashes into backslashes under Windows)

Shubham
2,8655 gold badges27 silver badges38 bronze badges
answered Aug 21, 2017 at 6:50

3 Comments

Do you have a source for parent not working on Windows? This seems to have been fixed sometime since you wrote this comment. It works fine for me using Python 3.7.2 on Windows 10.
i could get parent working on windows 10 with python 3.6.5. Which version of python are you talking about @Zhukovgeen?
@ggulgulia I believe it was 3.7
4

100% working answer:

os.path.abspath(os.path.join(os.getcwd() ,"../.."))
answered Sep 20, 2021 at 17:01

1 Comment

Nope, that gets the directory two levels up relative to the current working directory, not the current module.
3

Surprisingly it seems no one has yet explored this nice one-liner option:

import os
two_up = os.path.normpath(__file__).rsplit(os.sep, maxsplit=2)[0]

rsplit is interesting since the maxsplit parameter directly represents how many parent folders to move up and it always returns a result in just one pass through the path.

answered Dec 14, 2021 at 5:34

Comments

2

I have found that the following works well in 2.7.x

import os
two_up = os.path.normpath(os.path.join(__file__,'../'))
answered Jan 31, 2017 at 18:08

Comments

2

You can use this as a generic solution:

import os
def getParentDir(path, level=1):
 return os.path.normpath( os.path.join(path, *([".."] * level)) )
answered Apr 16, 2017 at 19:47

3 Comments

@JanSila: can be more specific, why is it not pythonic? For readability, it could have more comments what this does, yes - but in the end it's using standard python language features, see e.g. stackoverflow.com/questions/36901
It is a little dense, but I don't think this is too abstract and not readable. It is just a generalized version of other answers posted here. I would like a standard library way of doing things without the need for implementing a function, though.
Gives the path relative to the working directory not module
2

(pathlib.Path('../../') ).resolve()

answered May 1, 2020 at 18:29

1 Comment

Gives the path relative to the working directory not module
2

There is already an accepted answer, but for two levels up I think a chaining approach is arguably more readable:

pathlib.Path(__file__).parent.parent.resolve()
answered Nov 4, 2021 at 9:25

2 Comments

This has already been mentioned in some of the other answers. When answering older questions that already have answers, please make sure you provide either a novel solution or a significantly better explanation than existing answers.
No, it hasn't been mentioned for pathlib.
1

Assuming you want to access folder named xzy two folders up your python file. This works for me and platform independent.

".././xyz"

answered Jan 24, 2020 at 18:18

1 Comment

Gives the path relative to the working directory not module
1

With Pathlib (recommended after Python 3.5, the/a general solution that works not only in file.py files, but also in Jupyter (or other kind of) notebook and Python shell is:

p = Path.cwd().resolve().parents[1]

You only need to substitute (__file__) for cwd() (current working directory).

Indeed it would even work just with:

p = Path().resolve().parents[1]

(and of course with .parent.parent instead of parents[1])

answered Jan 20, 2022 at 0:51

Comments

1

Only with os.path

os.path.abspath(os.path.join(os.path.dirname(__file__),"../.."))
answered Jun 12, 2023 at 16:05

Comments

0

pathlib: Path.parts is more flexible then Path.parents

what library to use

I would recommend using pathlib.Path. Its the modern and object oriented way of handling paths in python.

Hence pathlib is the first proposed library for File and Directory Access in the python docs: https://docs.python.org/3/library/filesys.html

how to handle paths

I want to point out the option to use the parts method. Simply because its a bit more flexible.

With parents, you start at the end of the path and navigate upwards. It is not really pratical to get up to the root of the path, as negative indexing is not supported.

With parts on the other hand side, you simply split the path into a tuple and can operate on with with all list operations python offers.

>>> from pathlib import Path
>>> p = Path("/a/b/c/d/e.txt")
>>> p.parts
('/', 'a', 'b', 'c', 'd', 'e.txt')

So a small comparison of different usecases with parts and parents:

# get two levels up
>>> p.parents[1]
PosixPath('/a/b/c')
>>> Path(*p.parts[:-2])
PosixPath('/a/b/c')
# get second level after root
>>> p.parents[len(p.parents) - 3]
PosixPath('/a/b')
>>> Path(*p.parts[:3])
PosixPath('/a/b')
# unfortunately negative indexing is not supported for the parents method
>>> p.parents[-3]
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "/home/user/.conda/envs/space221118/lib/python3.8/pathlib.py", line 620, in __getitem__
 raise IndexError(idx)
IndexError: -3
answered Aug 22, 2023 at 10:17

Comments

-1

I don't yet see a viable answer for 2.7 which doesn't require installing additional dependencies and also starts from the file's directory. It's not nice as a single-line solution, but there's nothing wrong with using the standard utilities.

import os
grandparent_dir = os.path.abspath( # Convert into absolute path string
 os.path.join( # Current file's grandparent directory
 os.path.join( # Current file's parent directory
 os.path.dirname( # Current file's directory
 os.path.abspath(__file__) # Current file path
 ),
 os.pardir
 ),
 os.pardir
 )
)
print grandparent_dir

And to prove it works, here I start out in ~/Documents/notes just so that I show the current directory doesn't influence outcome. I put the file grandpa.py with that script in a folder called "scripts". It crawls up to the Documents dir and then to the user dir on a Mac.

(testing)AlanSE-OSX:notes AlanSE$ echo ~/Documents/scripts/grandpa.py 
/Users/alancoding/Documents/scripts/grandpa.py
(testing)AlanSE-OSX:notes AlanSE$ python2.7 ~/Documents/scripts/grandpa.py 
/Users/alancoding

This is the obvious extrapolation of the answer for the parent dir. Better to use a general solution than a less-good solution in fewer lines.

answered Dec 22, 2016 at 16:29

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.