140
votes

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__),".."))
11
So you want to get blog1 or a ? And where is your current file located? - Felix Kling
do you understand what your code is doing? - SilentGhost
yes , it get the templates/blog1/page.html - zjm1126
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
@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

11 Answers

190
votes

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))).

62
votes

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'
54
votes

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]
13
votes
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'))
9
votes

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

6
votes

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
3
votes

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__)),"..",".."))
3
votes

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.

1
votes

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
0
votes

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'
0
votes

I tried:

import os
os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))), os.pardir))