170

this code is get the templates/blog1/page.html in b.py:

path = os.path.join(os.path.dirname(__file__), os.path.join('templates', 'blog1/page.html'))

but i want to get the parent dir location:

aParent
   |--a
   |  |---b.py
   |      |---templates
   |              |--------blog1
   |                         |-------page.html
   |--templates
          |--------blog1
                     |-------page.html

and how to get the aParent location

thanks

updated:

this is right:

dirname=os.path.dirname
path = os.path.join(dirname(dirname(__file__)), os.path.join('templates', 'blog1/page.html'))

or

path = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
Tim
  • 41,901
  • 18
  • 127
  • 145
zjm1126
  • 63,397
  • 81
  • 173
  • 221
  • 2
    So you want to get `blog1` or `a` ? And where is your current file located? – Felix Kling May 12 '10 at 09:03
  • do you understand what your code is doing? – SilentGhost May 12 '10 at 09:07
  • 2
    yes , it get the templates/blog1/page.html – zjm1126 May 12 '10 at 09:09
  • `os.path.join('templates', 'blog1/page.html')` looks strange to me. You are mixing things up. Either `os.path.join('templates', 'blog1', 'page.html')` or `'templates/blog1/page.html'`. And much easier would be `os.path.abspath(os.path.join('templates', 'blog1', 'page.html'))` then – Felix Kling May 12 '10 at 09:15
  • 1
    @zjm: no, you don't *get* that page. It's not some blackbox that you could just use to get the template file. It performs a series of trivial small steps, and if you could understand them, you wouldn't have this question. – SilentGhost May 12 '10 at 09:20
  • so how to get the page and the 'a' dir location ?? – zjm1126 May 12 '10 at 09:26

12 Answers12

222

You can apply dirname repeatedly to climb higher: dirname(dirname(file)). This can only go as far as the root package, however. If this is a problem, use os.path.abspath: dirname(dirname(abspath(file))).

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • 43
    I know the OP knows about `dirname`. It isn't obvious to everyone that applying dirname to a directory yields the parent directory. – Marcelo Cantos May 12 '10 at 09:09
  • 6
    `dirname` does **NOT** always return the parent directory; http://twitter.com/#!/ActiveState/status/671049326788608 – Sridhar Ratnakumar Nov 05 '10 at 22:12
  • 2
    @Sridhar: That depends on your perspective; I consider a path ending in `/` as not representing the leaf directory entry itself, but its contents, which is why, e.g., `mv xxx yyy/` fails if `yyy` isn't a preexisting directory. In any case, even if we take your point as a given, it is irrelevant in the context of my answer. Neither `file` nor the result of `dirname` will ever end in a `/`. – Marcelo Cantos Nov 06 '10 at 00:56
  • 1
    Minor correction: `dirname` may return `'/'`, which clearly ends in a `/`. That is the only exception, AFAIK. – Marcelo Cantos Feb 06 '13 at 23:19
74

Use relative path with the pathlib module in Python 3.4+:

from pathlib import Path

Path(__file__).parent

You can use multiple calls to parent to go further in the path:

Path(__file__).parent.parent

As an alternative to specifying parent twice, you can use:

Path(__file__).parents[1]
Gavriel Cohen
  • 4,355
  • 34
  • 39
68

os.path.abspath doesn't validate anything, so if we're already appending strings to __file__ there's no need to bother with dirname or joining or any of that. Just treat __file__ as a directory and start climbing:

# climb to __file__'s parent's parent:
os.path.abspath(__file__ + "/../../")

That's far less convoluted than os.path.abspath(os.path.join(os.path.dirname(__file__),"..")) and about as manageable as dirname(dirname(__file__)). Climbing more than two levels starts to get ridiculous.

But, since we know how many levels to climb, we could clean this up with a simple little function:

uppath = lambda _path, n: os.sep.join(_path.split(os.sep)[:-n])

# __file__ = "/aParent/templates/blog1/page.html"
>>> uppath(__file__, 1)
'/aParent/templates/blog1'
>>> uppath(__file__, 2)
'/aParent/templates'
>>> uppath(__file__, 3)
'/aParent'
joemaller
  • 19,579
  • 7
  • 67
  • 84
  • 3
    This is nice, but it would also be cool if the standard library added a convenience function that accomplished this...don't want to come to SO every time I need this func – Julian Irwin Jan 27 '16 at 17:26
  • 6
    Would `os.path.abspath(os.path.join(__file__, "..", "..")` be more portable? – slowD Aug 31 '18 at 00:28
13
os.path.dirname(os.path.abspath(__file__))

Should give you the path to a.

But if b.py is the file that is currently executed, then you can achieve the same by just doing

os.path.abspath(os.path.join('templates', 'blog1', 'page.html'))
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
9

os.pardir is a better way for ../ and more readable.

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

This will return the parent path of the given_path

Sun Liwen
  • 1,224
  • 1
  • 15
  • 21
6

A simple way can be:

import os
current_dir =  os.path.abspath(os.path.dirname(__file__))
parent_dir = os.path.abspath(current_dir + "/../")
print parent_dir
Muneeb Ali
  • 2,056
  • 1
  • 16
  • 8
3

May be join two .. folder, to get parent of the parent folder?

path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)),"..",".."))
YOU
  • 120,166
  • 34
  • 186
  • 219
2

Here is another relatively simple solution that:

  • does not use dirname() (which does not work as expected on one level arguments like "file.txt" or relative parents like "..")
  • does not use abspath() (avoiding any assumptions about the current working directory) but instead preserves the relative character of paths

it just uses normpath and join:

def parent(p):
    return os.path.normpath(os.path.join(p, os.path.pardir))

# Example:
for p in ['foo', 'foo/bar/baz', 'with/trailing/slash/', 
        'dir/file.txt', '../up/', '/abs/path']:
    print parent(p)

Result:

.
foo/bar
with/trailing
dir
..
/abs
Stefaan
  • 4,696
  • 3
  • 23
  • 16
2

Use the following to jump to previous folder:

os.chdir(os.pardir)

If you need multiple jumps a good and easy solution will be to use a simple decorator in this case.

Zulu
  • 8,765
  • 9
  • 49
  • 56
Marco smdm
  • 1,020
  • 1
  • 15
  • 25
1

from os.path import basename, dirname
basename(dirname('foo/bar/foo_bar'))

Ernest
  • 11
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 03 '22 at 21:54
0

I think use this is better:

os.path.realpath(__file__).rsplit('/', X)[0]


In [1]: __file__ = "/aParent/templates/blog1/page.html"

In [2]: os.path.realpath(__file__).rsplit('/', 3)[0]
Out[3]: '/aParent'

In [4]: __file__ = "/aParent/templates/blog1/page.html"

In [5]: os.path.realpath(__file__).rsplit('/', 1)[0]
Out[6]: '/aParent/templates/blog1'

In [7]: os.path.realpath(__file__).rsplit('/', 2)[0]
Out[8]: '/aParent/templates'

In [9]: os.path.realpath(__file__).rsplit('/', 3)[0]
Out[10]: '/aParent'
dongweiming
  • 811
  • 1
  • 8
  • 8
  • Not quite, it's OS dependent (will not work on Windows). Also it does not allow to use relative paths. – kgadek Oct 22 '14 at 17:49
0

I tried:

import os
os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))), os.pardir))
gogasca
  • 9,283
  • 6
  • 80
  • 125