How do I get the parent directory in Python?
Asked Answered
F

21

548

Could someone tell me how to get the parent directory of a path in Python in a cross platform way. E.g.

C:\Program Files ---> C:\

and

C:\ ---> C:\

If the directory doesn't have a parent directory, it returns the directory itself. The question might seem simple but I couldn't dig it up through Google.

Freewheel answered 18/5, 2010 at 18:55 Comment(1)
M
782

Python 3.4

Use the pathlib module.

from pathlib import Path
path = Path("/here/your/path/file.txt")
print(path.parent.absolute())

Old answer

Try this:

import os
print os.path.abspath(os.path.join(yourpath, os.pardir))

where yourpath is the path you want the parent for.

Marlo answered 18/5, 2010 at 19:0 Comment(12)
Your answer is correct but convoluted; os.path.dirname is the function for this, like a+=5-4 is more convoluted than a+=1. The question requested only the parent directory, not whether is exists or the true parent directory assuming symbolic links get in the way.Profession
I tried to change the code snippet to os.pardir, but unfortunately Stack Overflow "Edits must be at least 6 non-space characters". It seems smart enough to detect whitespace padding; maybe the OP can correct this someday...Escurial
@tzot: unfortunately os.path.dirname gives different results depending on whether a trailing slash is included in the path. If you want reliable results you need to use the os.path.join method in answer above.Siriasis
@Siriasis Thanks. Your comment should be appended in the answer for its completeness' sake.Profession
@tzot: I guess the OP wanted to know how to move from one subdirectory to its parent. But dirname only returns the directory part of the full pathname to a file by removing the last component auf the path string (here: ../pardir) via split. abspath on the other hand correctly interprets and resolves .. as a reference to the top-level directory, which, I guess, is what the OP really asked for.Aground
Since this is apparently complicated enough to warrant a StackOverflow question, I feel that this should be added to the os.path library as a built-in function.Ardath
Don't miss @benjarobin's solution below if you are interested to keep relative path relative.Alurd
This doesn't work if you are trying to work with paths on a different file systemManducate
Try from pathlib import Path and next print((Path().parent.absolute()).parent)Berkeley
Path("/here/your/path/file.txt") does not work. Error message: 'WindowsPath' object is not callableBiotype
I prefer os.path.dirname since it gave me the path in linux format when converting back to string. May not matter for most people but the Pathlib way gave me it back in stinky windows format on my pcSpeciosity
Works fine. print(os.path.abspath(os.path.join(yourpath, os.pardir))) No need 'pathlib', enough os packages.Cyprinodont
T
404

Using os.path.dirname:

>>> os.path.dirname(r'C:\Program Files')
'C:\\'
>>> os.path.dirname('C:\\')
'C:\\'
>>>

Caveat: os.path.dirname() gives different results depending on whether a trailing slash is included in the path. This may or may not be the semantics you want. Cf. @kender's answer using os.path.join(yourpath, os.pardir).

Thrawn answered 18/5, 2010 at 19:14 Comment(9)
os.path.dirname(r'C:\Program Files') what? Python's just giving you the directory where the file 'Program Files' would be. What's more, it doesn't even have to exist, behold: os.path.dirname(r'c:\i\like\to\eat\pie') outputs 'c:\\i\\like\\to\\eat'Provenance
The original poster does not state that the directory have to exist. There are a lot of pathname methods that does nothing but string manipulation. To verify if the pathname actually exist requires a disk access. Depends on the application this may or may not be desirable.Thrawn
Seems that this would be a good solution if you knew that the input directory was valid (which can be checked).Vander
Most of the other provided solutions don't check if the parent exists either (as most os.path functions are indeed string manipulations only), so no big loss here. And all the other solutions here seem unnecessary complex to me, so I'm upvoting this one :) Btw, imho the os.path is one of the worst classes for python (especially implementation-wise -- platform-independence screwed up is where it hurted me most :( )Valentia
this solution is sensitive to trailing os.sep. Say os.sep=='/'. dirname(foo/bar) -> foo, but dirname(foo/bar/) -> foo/barRommel
That's by design. It comes down to the interpretation of a path with a trailing /. Do you consider "path1" equals to "path1/"? The library use the most general interpretation that they are distinct. In some context people may want to treat them as equivalent. In this case you can do a rstrip('/') first. Had the library pick the other interpretation you will lost fidelity.Thrawn
@WaiYipTung "Do you consider "path1" equals to "path1/"" --> Yes, because they are. In what context would you ever not treat them as equivalent?Nubilous
@Ryan, I don't know about that. There is an entire RFC 1808 written to address the issue of relative path in URI and all the subtlety of the presence and absence of a trailing /. If you know of any documentation that says they should be treated equivalent in general please point it out.Thrawn
@WaiYipTung Hmm, okay, seems silly but I thought this was just a library decision. Makes more sense then.Nubilous
L
163

Using Pathlib (available since )

from pathlib import Path
Path('C:\Program Files').parent
# Returns a Pathlib object

The traditional method

import os.path
os.path.dirname('C:\Program Files')
# Returns a string

Which method should I use?

Use the traditional method if:

  • You are worried about existing code generating errors if it were to use a Pathlib object. (Since Pathlib objects cannot be concatenated to strings. Pathlib objects can be concatenated to Pathlib objects, so if you are starting a new project and use Pathlib everywhere, you will be fine.)

  • Your Python version is less than 3.4.

  • You're putting together filepaths for uses outside of the current Python program (sending the path to other services running on the machine, storing the path in a database, etc.), and you haven't been given any Pathlib objects to start with. Say for example that you have a filepath, it is currently a string, and you want to get the parent directory so you can put it in some JSON. It would be kind of silly to convert to a Pathlib object and back again just for that.

If none of the above apply, use Pathlib.



What is Pathlib?

If you don't know what Pathlib is, the Pathlib module is a terrific module that makes working with files even easier for you. Most if not all of the built in Python modules that work with files will accept both Pathlib objects and strings. I've highlighted below a couple of examples from the Pathlib documentation that showcase some of the neat things you can do with Pathlib.

Navigating inside a directory tree:

>>> p = Path('/etc')
>>> q = p / 'init.d' / 'reboot'
>>> q
PosixPath('/etc/init.d/reboot')
>>> q.resolve()
PosixPath('/etc/rc.d/init.d/halt')

Querying path properties:

>>> q.exists()
True
>>> q.is_dir()
False
Locule answered 19/3, 2015 at 4:44 Comment(3)
This is the only sane answer. If you're forced to use Python 2, just pip install pathlib2 and use the backport.Suboxide
This solution is NOT sensitive to trailing os.sep!Scullion
You don't really have to "worry about existing code generating errors if it were to use a Pathlib object" because you can just wrap the pathlib object: path_as_string = str(Path(<somepath>)).Nodule
L
50
import os
p = os.path.abspath('..')

C:\Program Files ---> C:\\\

C:\ ---> C:\\\

Last answered 18/5, 2010 at 19:0 Comment(3)
This only gets the parent of the CWD, not the parent of an arbitrary path as the OP asked.Indemonstrable
Add the double dots at the end of your URL and it will work E.g os.path.abspath(r'E:\O3M_Tests_Embedded\branches\sw_test_level_gp\test_scripts\..\..') Result: E:\\O3M_Tests_Embedded\\branchesSaez
This means: /.Congregation
M
36

An alternate solution of @kender

import os
os.path.dirname(os.path.normpath(yourpath))

where yourpath is the path you want the parent for.

But this solution is not perfect, since it will not handle the case where yourpath is an empty string, or a dot.

This other solution will handle more nicely this corner case:

import os
os.path.normpath(os.path.join(yourpath, os.pardir))

Here the outputs for every case that can find (Input path is relative):

os.path.dirname(os.path.normpath('a/b/'))          => 'a'
os.path.normpath(os.path.join('a/b/', os.pardir))  => 'a'

os.path.dirname(os.path.normpath('a/b'))           => 'a'
os.path.normpath(os.path.join('a/b', os.pardir))   => 'a'

os.path.dirname(os.path.normpath('a/'))            => ''
os.path.normpath(os.path.join('a/', os.pardir))    => '.'

os.path.dirname(os.path.normpath('a'))             => ''
os.path.normpath(os.path.join('a', os.pardir))     => '.'

os.path.dirname(os.path.normpath('.'))             => ''
os.path.normpath(os.path.join('.', os.pardir))     => '..'

os.path.dirname(os.path.normpath(''))              => ''
os.path.normpath(os.path.join('', os.pardir))      => '..'

os.path.dirname(os.path.normpath('..'))            => ''
os.path.normpath(os.path.join('..', os.pardir))    => '../..'

Input path is absolute (Linux path):

os.path.dirname(os.path.normpath('/a/b'))          => '/a'
os.path.normpath(os.path.join('/a/b', os.pardir))  => '/a'

os.path.dirname(os.path.normpath('/a'))            => '/'
os.path.normpath(os.path.join('/a', os.pardir))    => '/'

os.path.dirname(os.path.normpath('/'))             => '/'
os.path.normpath(os.path.join('/', os.pardir))     => '/'
Madras answered 4/9, 2014 at 15:56 Comment(2)
Normalizing the path is always a good practice, especially when doing cross-platform work.Smail
@Alurd This solution was not perfect, I did improved it since the orginal solution does not handle one caseMadras
F
20
os.path.split(os.path.abspath(mydir))[0]
Felten answered 18/5, 2010 at 18:58 Comment(6)
This won't work for paths which are to a directory, it'll just return the directory again.Abstention
@AnthonyBriggs, I just tried this using Python 2.7.3 on Ubuntu 12.04 and it seems to work fine. os.path.split(os.path.abspath("this/is/a/dir/"))[0] returns '/home/daniel/this/is/a' as expected. I don't at the moment have a running Windows box to check there. On what setup have you observed the behavior that you report?Felten
You could do parentdir = os.path.split(os.path.apspath(dir[:-1]))[0]. This - I am certain - works because if there is a slash on the end, then it is removed; if there is no slash, this will still work (even if the last part of the path is only one char long) because of the preceding slash. This of course assumes that the path is proper and not say something like /a//b/c///d//// (in unix this is valid still), which in most cases they are (proper) especially when you do something like os.path.abspath or any other os.path function.Flaxman
Also, to counteract a lot of slashes on the end, you could just write a small for loop that removes those. I'm sure there could even be a clever one-liner to do it, or maybe do that and os.path.split in one line.Flaxman
@Den Menes I just saw you comment. It doesn't work if you have something like os.path.split("a/b//c/d///") and, for example, cd //////dev////// is equivalent to cd /dev/` or cd /dev; all of these are valid in linux. I just came up with this and it may be useful, though: os.path.split(path[:tuple(ind for ind, char in enumerate(path) if char != "/" and char != "\\")[-1]])[0]. (This essentially searches for the last non-slash, and gets the substring of the path up to that char.) I used path = "/a//b///c///d////" and then ran the aforementioned statement and got '/a//b///c'.Flaxman
With the understanding that the line above is for demonstration, I'd still recommend to not use "dir" as a variable/reference. It is also a built-in function.Smail
L
16
os.path.abspath(os.path.join(somepath, '..'))

Observe:

import posixpath
import ntpath

print ntpath.abspath(ntpath.join('C:\\', '..'))
print ntpath.abspath(ntpath.join('C:\\foo', '..'))
print posixpath.abspath(posixpath.join('/', '..'))
print posixpath.abspath(posixpath.join('/home', '..'))
Lucky answered 18/5, 2010 at 18:58 Comment(1)
Does not work with Symbolic linksMoen
I
10
import os
print"------------------------------------------------------------"
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
print("example 1: "+SITE_ROOT)
PARENT_ROOT=os.path.abspath(os.path.join(SITE_ROOT, os.pardir))
print("example 2: "+PARENT_ROOT)
GRANDPAPA_ROOT=os.path.abspath(os.path.join(PARENT_ROOT, os.pardir))
print("example 3: "+GRANDPAPA_ROOT)
print "------------------------------------------------------------"
Inexplicit answered 22/2, 2013 at 23:6 Comment(0)
W
10
>>> import os
>>> os.path.basename(os.path.dirname(<your_path>))

For example in Ubuntu:

>>> my_path = '/home/user/documents'
>>> os.path.basename(os.path.dirname(my_path))
# Output: 'user'

For example in Windows:

>>> my_path = 'C:\WINDOWS\system32'
>>> os.path.basename(os.path.dirname(my_path))
# Output: 'WINDOWS'

Both examples tried in Python 2.7

Watchband answered 3/4, 2018 at 12:44 Comment(0)
B
9

Suppose we have directory structure like

1]

/home/User/P/Q/R

We want to access the path of "P" from the directory R then we can access using

ROOT = os.path.abspath(os.path.join("..", os.pardir));

2]

/home/User/P/Q/R

We want to access the path of "Q" directory from the directory R then we can access using

ROOT = os.path.abspath(os.path.join(".", os.pardir));
Bohn answered 10/8, 2019 at 13:31 Comment(0)
P
6

If you want only the name of the folder that is the immediate parent of the file provided as an argument and not the absolute path to that file:

os.path.split(os.path.dirname(currentDir))[1]

i.e. with a currentDir value of /home/user/path/to/myfile/file.ext

The above command will return:

myfile

Photothermic answered 29/8, 2015 at 10:2 Comment(1)
os.path.basename(os.path.dirname(current_dir)) also works here.Smail
N
4
import os

dir_path = os.path.dirname(os.path.realpath(__file__))
parent_path = os.path.abspath(os.path.join(dir_path, os.pardir))
Nievesniflheim answered 5/11, 2016 at 5:1 Comment(0)
H
3
import os.path

os.path.abspath(os.pardir)
Harriette answered 30/7, 2014 at 14:8 Comment(1)
This presumes you want the parent directory of "the current working directory" and not the parent directory any path in general.Smail
S
3

Just adding something to the Tung's answer (you need to use rstrip('/') to be more of the safer side if you're on a unix box).

>>> input1 = "../data/replies/"
>>> os.path.dirname(input1.rstrip('/'))
'../data'
>>> input1 = "../data/replies"
>>> os.path.dirname(input1.rstrip('/'))
'../data'

But, if you don't use rstrip('/'), given your input is

>>> input1 = "../data/replies/"

would output,

>>> os.path.dirname(input1)
'../data/replies'

which is probably not what you're looking at as you want both "../data/replies/" and "../data/replies" to behave the same way.

Salamis answered 16/11, 2015 at 5:19 Comment(1)
I would recommend to not use "input" as a variable/reference. It is a built-in function.Smail
K
2
print os.path.abspath(os.path.join(os.getcwd(), os.path.pardir))

You can use this to get the parent directory of the current location of your py file.

Knickers answered 3/5, 2011 at 15:24 Comment(2)
That suggestion often leads to bugs. os.getcwd() is often NOT where "your py file" is. Think packages. If I "import some_package_with_subpackages" many modules will not be in that package's top-most directory. os.getcwd() returns where you execute top-most script. And that also presumes you are doing it from a command line.Smail
Like DevPlayer noted os.getcwd() is not necessarily the location of your python file. sys.argv[0] is what you're looking for.Mould
G
1
import os 

def parent_directory():
  # Create a relative path to the parent of the current working directory 
  relative_parent = os.path.join(os.getcwd(), "..") # .. means parent directory

  # Return the absolute path of the parent directory
  return os.path.abspath(relative_parent)

print(parent_directory())
Gannie answered 13/6, 2022 at 12:26 Comment(0)
N
0

GET Parent Directory Path and make New directory (name new_dir)

Get Parent Directory Path

os.path.abspath('..')
os.pardir

Example 1

import os
print os.makedirs(os.path.join(os.path.dirname(__file__), os.pardir, 'new_dir'))

Example 2

import os
print os.makedirs(os.path.join(os.path.dirname(__file__), os.path.abspath('..'), 'new_dir'))
Nightshirt answered 21/4, 2014 at 12:2 Comment(0)
S
0
os.path.abspath('D:\Dir1\Dir2\..')

>>> 'D:\Dir1'

So a .. helps

Saez answered 2/7, 2014 at 16:2 Comment(0)
S
0
import os

def parent_filedir(n):
    return parent_filedir_iter(n, os.path.dirname(__file__))

def parent_filedir_iter(n, path):
    n = int(n)
    if n <= 1:
        return path
    return parent_filedir_iter(n - 1, os.path.dirname(path))

test_dir = os.path.abspath(parent_filedir(2))
Sharenshargel answered 8/9, 2016 at 1:35 Comment(0)
F
0

The answers given above are all perfectly fine for going up one or two directory levels, but they may get a bit cumbersome if one needs to traverse the directory tree by many levels (say, 5 or 10). This can be done concisely by joining a list of N os.pardirs in os.path.join. Example:

import os
# Create list of ".." times 5
upup = [os.pardir]*5
# Extract list as arguments of join()
go_upup = os.path.join(*upup)
# Get abspath for current file
up_dir = os.path.abspath(os.path.join(__file__, go_upup))
Filicide answered 1/8, 2018 at 8:21 Comment(0)
E
0

To find the parent of the current working directory:

import pathlib
pathlib.Path().resolve().parent
Everest answered 20/9, 2021 at 19:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.