I am refactoring with
nbdev a library that creates a web page. They use
__file__ to locate web assets they want to copy.
__file__ dunder attribute shows the path of a module:
When a module is loaded from a file in Python,
__file__ is set to its path. (source)
Unfortunately, notebooks don’t know about this:
NameError: name '__file__' is not defined
Of course, code with
nbdev should work both in a notebook and as a module.
I learned from this Github issue that
globals()['dh'] gives the notebook’s directory. You can also get the
cwd various ways, but people mention there’s some risks there.
I’ve resorted to this try/except block:
try: src = Path(__file__).resolve()
except NameError as e: src = globals()['_dh']
Has this come up for anyone else? Any suggestions of a way to get the code’s location that works in both notebook and module environment?
Personally I just have a non-exported cell in my NB that defines it when I need it.
This would work great if I only want to copy the web assets when I’m developing the library/doing exploratory work. But in this case, the library should also copy web assets when it’s run as a pip install.
A user might do:
pip install clip-plot
clip-plot --images <folder of images>
clip-plot should generate an “embedding projector” style of visualization for their images, including copying web assets to their working directory.
try/except works as far as I can tell, so this isn’t a major issue, just wondered if there was a more standard way. Good reminder about using non-exported cells as I’m just getting into
nbdev (and developing a library for that matter).
I might be missing something - but wouldn’t a pip-installed version be a module, so have
Yes, exactly – so I was just looking for a way to write this in the notebook originally that would also work in the pip-installed module.
__file__ works in the pip-installed module, but not the notebook;
globals()['_dh'] works in the notebook, but not the pip-installed module.
My suggestion works then right? In the notebook, the
__file__ you define manually works, and is not exported. In the exported file, the automatically created one works.
Ah, I didn’t understand! Now I get your solution:
In one cell:
__file__ = globals()['_dh'].as_posix()
In a later cell (or, to ensure this never gets executed before the hidden bit, could put in the first cell and change “hide” to “hideline”):
src = Path(__file__).resolve()
This is much more readable! Thank you! Sorry it took me a while to get my head around that.