Using Python's os.path, how do I go up one directory?

Question:

I recently upgrade Django from v1.3.1 to v1.4.

In my old settings.py I have

TEMPLATE_DIRS = (
    os.path.join(os.path.dirname( __file__ ), 'templates').replace('\', '/'),
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

This will point to /Users/hobbes3/Sites/mysite/templates, but because Django v1.4 moved the project folder to the same level as the app folders, my settings.py file is now in /Users/hobbes3/Sites/mysite/mysite/ instead of /Users/hobbes3/Sites/mysite/.

So actually my question is now twofold:

  1. How do I use os.path to look at a directory one level above from __file__. In other words, I want /Users/hobbes3/Sites/mysite/mysite/settings.py to find /Users/hobbes3/Sites/mysite/templates using relative paths.
  2. Should I be keeping the template folder (which has cross-app templates, like admin, registration, etc.) at the project /User/hobbes3/Sites/mysite level or at /User/hobbes3/Sites/mysite/mysite?
Asked By: hobbes3

||

Answers:

os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'templates'))

As far as where the templates folder should go, I don’t know since Django 1.4 just came out and I haven’t looked at it yet. You should probably ask another question on SE to solve that issue.

You can also use normpath to clean up the path, rather than abspath. However, in this situation, Django expects an absolute path rather than a relative path.

For cross platform compatability, use os.pardir instead of '..'.

Answered By: forivall

To get the folder of a file just use:

os.path.dirname(path) 

To get a folder up just use os.path.dirname again

os.path.dirname(os.path.dirname(path))

You might want to check if __file__ is a symlink:

if os.path.islink(__file__): path = os.readlink (__file__)
Answered By: jassinm

You want exactly this:

BASE_DIR = os.path.join( os.path.dirname( __file__ ), '..' )
Answered By: Alan Viars
from os.path import dirname, realpath, join
join(dirname(realpath(dirname(__file__))), 'templates')

Update:

If you happen to “copy” settings.py through symlinking, @forivall’s answer is better:

~user/
    project1/  
        mysite/
            settings.py
        templates/
            wrong.html

    project2/
        mysite/
            settings.py -> ~user/project1/settings.py
        templates/
            right.html

The method above will ‘see’ wrong.html while @forivall’s method will see right.html

In the absense of symlinks the two answers are identical.

Answered By: Antony Hatchkins

For a paranoid like me, I’d prefer this one

TEMPLATE_DIRS = (
    __file__.rsplit('/', 2)[0] + '/templates',
)
Answered By: haterh

Personally, I’d go for the function approach

def get_parent_dir(directory):
    import os
    return os.path.dirname(directory)

current_dirs_parent = get_parent_dir(os.getcwd())
Answered By: Lord Sumner

I think the easiest thing to do is just to reuse dirname()
So you can call

os.path.dirname(os.path.dirname( __file__ ))

if you file is at /Users/hobbes3/Sites/mysite/templates/method.py

This will return “/Users/hobbes3/Sites/mysite”

Answered By: pythonHelpRequired

This might be useful for other cases where you want to go x folders up. Just run walk_up_folder(path, 6) to go up 6 folders.

def walk_up_folder(path, depth=1):
    _cur_depth = 1        
    while _cur_depth < depth:
        path = os.path.dirname(path)
        _cur_depth += 1
    return path   
Answered By: Marcus Krautwurst

If you are using Python 3.4 or newer, a convenient way to move up multiple directories is pathlib:

from pathlib import Path

full_path = "path/to/directory"
str(Path(full_path).parents[0])  # "path/to"
str(Path(full_path).parents[1])  # "path"
str(Path(full_path).parents[2])  # "."
Answered By: birnbaum

To go n folders up… run up(n)

import os

def up(n, nth_dir=os.getcwd()):
    while n != 0:
        nth_dir = os.path.dirname(nth_dir)
        n -= 1
    return nth_dir
Answered By: Jo3l

Of course: simply use os.chdir(..).

Answered By: The Shwarma

With using os.path we can go one directory up like that

one_directory_up_path = os.path.dirname('.')

also after finding the directory you want you can join with other file/directory path

other_image_path = os.path.join(one_directory_up_path, 'other.jpg')
Answered By: abdullahselek

Go up a level from the work directory

import os
os.path.dirname(os.getcwd())

or from the current directory

import os
os.path.dirname('current path')
Answered By: Julio CamPlaz

From the current file path you could use:

os.path.join(os.path.dirname(__file__),'..','img','banner.png')

I’m surprised handling for an arbitrary number of ".." parent directory tokens in a path string isn’t directly handled for by the os library. Here’s a quick and dirty function that’ll give you an absolute path string from a relative one:

def get_abs_from_relpath(relpath:str) -> str:
    ap = os.path.abspath(__file__).split("/")[:-1]
    sp = relpath.split("/")
    sp_start_index = 0
    for slug in sp:
        if slug == "..":
            ap.pop(-1)
            sp_start_index += 1
        else:
            return "/".join(ap+sp[sp_start_index:])

You can call it with open() like this:

with open(get_abs_from_relpath('../../../somedir/myfile.txt')) as f:
    foo = f.read()
Answered By: Alan Garcia

If you prefer a one-liner for getting the parent directory, I’d suggest this:

import os
    
parent_dir = os.path.split(os.getcwd())[0]

os.path.split() method returns a tuple (head, tail) where tail is everything after the final slash. So the first index is the parent of your absolute path.

Answered By: carlosgg

Not an answer but a long tangential comment that probably should be made as someone may be led astray…

The syntax os.path.join( os.path.dirname( __file__ ), 'foo.txt') to get a file within the same folder as the python file getting run is not the "advised" solution for packages, instead package data is preferred for a couple of reasons, for example in a zip packaged package or a more complicated filesystem.

pkg_resources.read_text(__package__, 'foo.txt') was the formerly recommended solution, but will be removed at some point and importlib.resources.read_text(__package__, 'foo.txt') is the recommended way —see https://docs.python.org/3/library/importlib.html#module-importlib.resources for the many options.
However, this

  • requires include_package_data=True and package_data with a Dict[str, List[str] in the setup.py file
  • requires a MANIFEST.in if pip distributed as sdist (but not a built wheel)
  • will not work for relative imports (i.e. not installed)
  • is wisely and generally ignored for sake of sanity in webapps due to the way they run
Answered By: Matteo Ferla
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.