Reputation: 6655
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!
Upvotes: 160
Views: 227065
Reputation: 10606
Path.parts
is more flexible then Path.parents
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
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
Upvotes: 0
Reputation: 2543
Only with os.path
os.path.abspath(os.path.join(os.path.dirname(__file__),"../.."))
Upvotes: 0
Reputation: 454
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]
)
Upvotes: 1
Reputation: 4370
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.
Upvotes: 3
Reputation: 51
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()
Upvotes: 1
Reputation: 202
100% working answer:
os.path.abspath(os.path.join(os.getcwd() ,"../.."))
Upvotes: 4
Reputation: 1763
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())
Upvotes: 11
Reputation: 29
Assuming you want to access folder named xzy two folders up your python file. This works for me and platform independent.
".././xyz"
Upvotes: 1
Reputation: 2150
Very easy:
Here is what you want:
import os.path as path
two_up = path.abspath(path.join(__file__ ,"../.."))
Upvotes: 83
Reputation: 573
The best solution (for python >= 3.4) when executing from any directory is:
from pathlib import Path
two_up = Path(__file__).resolve().parents[1]
Upvotes: 33
Reputation: 1648
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)
Upvotes: 4
Reputation: 15289
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.
Upvotes: 33
Reputation: 626
You can use this as a generic solution:
import os
def getParentDir(path, level=1):
return os.path.normpath( os.path.join(path, *([".."] * level)) )
Upvotes: 2
Reputation: 21
I have found that the following works well in 2.7.x
import os
two_up = os.path.normpath(os.path.join(__file__,'../'))
Upvotes: 2
Reputation: 2775
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.
Upvotes: -1
Reputation:
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()
Upvotes: 5
Reputation: 53678
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.
Upvotes: 219