161

I'm on a Jupyter Notebook server (v4.2.2) with Python 3.4.2 and I want to use the global name __file__, because the notebook will be cloned from other users and in one section I have to run:

def __init__(self, trainingSamplesFolder='samples', maskFolder='masks'):
    self.trainingSamplesFolder = self.__getAbsPath(trainingSamplesFolder)
    self.maskFolder = self.__getAbsPath(maskFolder)

def __getAbsPath(self, path):
    if os.path.isabs(path):
        return path
    else:
        return os.path.join(os.path.dirname(__file__), path)

The __getAbsPath(self, path) checks if a path param is a relative or absolute path and returns the absolute version of path. So I can use the returned path safely later.

But I get the error

NameError: name '__file__' is not defined

I searched for this error online and found the "solution" that I should better use sys.argv[0], but print(sys.argv[0]) returns

/usr/local/lib/python3.4/dist-packages/ipykernel/__main__.py

But the correct notebook location should be /home/ubuntu/notebooks/.

Thanks for the reference How do I get the current IPython Notebook name from Martijn Pieters (comments) the last answer (not accepted) fits perfect for my needs:

print(os.getcwd())

/home/ubuntu/notebooks

2

9 Answers 9

144

If you want to get path of the directory in which your script is running, I would highly recommend using,

os.path.abspath('')

Advantages

  • It works from Jupyter Notebook
  • It work from REPL
  • It doesn't require Python 3.4's pathlib

Please note that one scenario where __file__ has advantage is when you are invoking python from directory A but running script in directory B. In that case above as well as most other methods will return A, not B. However for Jupyter notbook, you always get folder for .ipyn file instead of the directory from where you launched jupyter notebook.

Sign up to request clarification or add additional context in comments.

5 Comments

This does not work for me. It gives me "working directory" instead when I run a notebook with papermill.
That surprising. In my testing all 3 scenario works. Could this because of papermill (I'm not familiar with it)?
@Shital, untidyhair is correct. This, like the other suggestion from mab below, does NOT work. It merely gives you the cwd.
Does not work - gives me working directory
This answer does not work when running a notebook inside VS Code if the CWD has been changed, e.g. by setting "jupyter.notebookFileRoot": "${workspaceFolder}". It returns the workspace directory, not the directory of the notebook file.
63

__file__ might not be available for you, but you can get current folder in which your notebook is located in different way, actually.

There are traces in global variables, if you will call globals() you will see that there is an element with the key _dh, that might help you. Here how I managed to load the data.csv file that is located in the same folder as my notebook:

import os

current_folder = globals()['_dh'][0]

# Calculating path to the input data
data_location = os.path.join(current_folder,'data.csv')

7 Comments

Wow, congratulations @shytikov, your method really works and should be the preferred answer. You have found a method that avoids the ugly JS hacks. Many, many thanks. Now, if we could get a way to get the notebook name...
It looks like this works in Notebook, but not in a regular Python interpreter, (at least when imported as a module). I switch between using Jupyter kernels and a regular Python interpreter, so I need something that works on both. I think I'm going to resort to an environment variable.
This works for me both in JupyterLab and Pycharm, while the other suggestions did not.
why not use os.getcwd() in lieu of globals()['_dh'][0]?
This didn't work for me when using papermill to execute the notebook from a different directory. Both os.getcwd() and globals()["_dh"] showed the directory from which I ran the papermill command, not the directory the notebook template or the directory the executed notebook would land
|
48

In modern Python (v3.4+) we can use pathlib to get the notebook's directory:

from pathlib import Path

cwd = Path().resolve()
# cwd == PosixPath('/path/to/this/jupyter/ipynb/file's/directory/')

# or this way, thanks @NunoAndré:
cwd = Path.cwd()
# cwd == PosixPath('/path/to/this/jupyter/ipynb/file's/directory/')



Update

@ShitalShah I cannot reproduce the error you are reporting. Jupyter notebook seems to work fine, regardless of the current working directory the application was started.

Example: file ~/dir1/dir2/untitled.ipynb and Jupyter notebook started in ~/dir1:

Jupyter notebook started in ~/dir1

Jupyter notebook started in ~/dir1/dir2:

Jupyter notebook started in ~/dir1/dir2

9 Comments

@ShitalShah please see the updated answer. Maybe you can clarify, what is the problem you are experiencing.
Path has a class method just for that: Path.cwd()
@mac, this DOES NOT work. If you change cwd in your notebook, then re-execute that cell, it will give you the new cwd, not the notbook's location. This is a sorely missing feature in Jupyter Notebook. I have to resort to a hack involving Javascript. What a PITA.
@mab: Try import os;os.chdir('path/to/new/dir'). If you now try both Path.cwd() and Path().resolve(), they both point to path/to/new/dir and not to the location of your notebook!
@mab, it is not possible to reliably do that, because the notebook interface allows you to execute cells in arbitrary order--which is a really nice feature BTW. You can save the directory at the beginning of your notebook. However, if you later use os.chdir, then re-execute the first cell in your notebook, you will still get the wrong answer.
|
20

It's not possible to get the path to the notebook. You may find a way to get it that only works in one environment (eg os.getcwd()), but it won't necessarily work if the notebook is loaded in a different way.

Instead, try to write the notebook so that it doesn't need to know its own path. If doing something like getting the pwd, then be sure to fail fast / print an error if this doesn't work, vs. just silently trying to continue on.

See also: https://github.com/ipython/ipython/issues/10123

2 Comments

you are right that it isn't possible to get the path to the notebook with os.getcwd(). This merely gets the cwd. If you have changed that in the notebook, then go back to that cell, you will not get the notebook directory. THIS IS A HUGE PROBLEM. And no, I disagree that you should write your script such that it doesn't need to know where it is. There are very good reasons to do that, such as making a copy to another location.
While it may not be straightforward to do what the OP requests, there are solid reasons to find the path. E.g. a bidirectional sync between python and a notebook using jupytext in which the path to ancillary files is critical. I'll want to find a reliable solution
4

I'm new to python, but this works for me.

You can get os.path.dirname(__file__) equivalence by:

sys.path[0]

4 Comments

Maybe I'm missing a case where this could fail, but under "standard" conditions this appears to be the best solution.
Works for me. Also works after os.chdir, unlike the accepted answer.
How is this not equivalent to os.getcwd() ? Sys.path[0] is literally "" isnt it ?
This does not work when the PYTHON_PATH environment variable has been set.
2

As mentioned in this post, we can use get_ipython to check if the script is executed from a Jupyter Notebook (.ipynb file) and then assume if not it is executed from a .py file instead. I found as mentioned here that we can use extract_module_locals to get the name of the current Jupyter Notebook running.

This works for me:

import os

try:
    from IPython import get_ipython, extract_module_locals        
    get_ipython

    print("Running from .ipynb file")        

    this_dir, this_filename = os.path.split("/".join(
        extract_module_locals()[1]["__vsc_ipynb_file__"].split("/")[-5:]
    ) )
    print(f'this_dir:\t {this_dir}')
    print(f'this_filename:\t {this_filename}')
    
except:
    print("Running from .py file")
    this_dir, this_filename = os.path.split(os.path.abspath(__file__) )
    print(f'this_dir:\t {this_dir}')
    print(f'this_filename:\t {this_filename}')

# Navigate to file located in one folder up:
os.path.abspath(os.path.join(os.path.dirname(this_dir), 'MyFile.xlsx'))

3 Comments

This is the only answer that works for me on VS Code running a notebook with a changed working directory, via the VS Code setting "jupyter.notebookFileRoot": "${workspaceFolder}". Thanks!
I suggest this simplification on the IPython side: from IPython import extract_module_locals; this_file = extract_module_locals()[1]["__vsc_ipynb_file__"]. And if you want the directory from that: import pathlib; this_dir = pathlib.Path(this_file).parent
Thanks, this works for me! I was just bothered that using this approach, the code needs to be inlined in the notebook and can't be defined in a function in a different file. I solved this by searching up the stack frame dynamically (extract_module_locals just calls sys._getframe(1) which doesn't work when the caller is in a different module than the notebook). Check out my answer for more details: stackoverflow.com/a/79656886/9905602
2

You can may get it by

import inspect
from pathlib import Path

module_path = Path(inspect.getframeinfo(inspect.currentframe()).filename).resolve()

It will not return currrent working directory, but path to module, even if module is imported from elsewhere.

As stated in comments, it may not work if you use it vie external tool like VS Code.

[EDITED]: I stated, that __file__ is available in new Jupyter. It's been my fault as t worked for me because of some tool I used over Jupyter (I do not remeber what tool...).

2 Comments

Six months later on jupyter 5.2.0 does not support __file__ . Which version are you referring to?
On Python 3.11 running a notebook inside VS Code this yields PosixPath('/private/var/folders/5k/8hy03lfs6fn3j4pg_l8_jvg00000gp/T/ipykernel_67431/2581620084.py')…which is definitely not where the .ipynb file is stored.
1

For Jupyter Notebooks, enclose the file with quotes i.e "file". Then use the dirname method to get the file DIR

import os

THIS_DIR = os.path.dirname(os.path.abspath("__file__"))
print(THIS_DIR)

# /home/brightkoech/Projects/EPL-Streamlit-Visualisation/src

1 Comment

This answer is misleading. It gives the false impression that the string __file__ has a special meaning to abspath. It has not. You can put any string you want there. What abspath is doing is just resolving the relative path given as an argument using the current working directory and then dirname will extract the dir. So this is completely equivalent to getcwd.
0

Building on the answer from https://stackoverflow.com/a/79058785/9905602, I wrote this helper function you can import in a notebook.

The cool thing about this solution is that you can put this function in any other file (e.g. notebook_utils.py) from which you can import the function and run it in your notebook.

import sys
from pathlib import Path
from types import FrameType

def find_notebook_file() -> Path | None:
    """Returns the path to the current notebook file, if available."""
    f: FrameType | None = sys._getframe()
    while f:
        if "__vsc_ipynb_file__" in f.f_locals:
            return Path(f.f_locals["__vsc_ipynb_file__"])
        f = f.f_back
    raise RuntimeError("Could not find '__vsc_ipynb_file__'. Are you running in a VSCode Jupyter notebook?")

The answer I referenced was using extract_module_locals which calls sys._getframe(1). This works if you define the function in your notebook but breaks if it is defined in another file and imported in the notebook because then the call to extract_module_locals still accesses the calling frame but then the caller is not the notebook cell directly, but rather the function inside the module. That causes that now you are one or more frames away from where __vsc_ipynb_file__ is. The depth argument of sys._getframe doesn't account for this, but my solution solves this by searching up the stack frame dynamically.

This way, my solution works both when defined inline in the notebook or when defined elsewhere and imported in the notebook.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.