TheLoserIsOp
TheLoserIsOp

Reputation: 11

Get Path To File of Caller From Within Library

I want to be able to get the path to the file which is importing my python library. How can I do that?

For example:

The user creates a file at C:\Users\Bob\bobsproject\main.py. From within the library, I want to be able to get the path to the file, and read it as a txt. How can I do that?

Upvotes: 0

Views: 114

Answers (1)

Mad Physicist
Mad Physicist

Reputation: 114310

If you want to get the name of the driver script that is (possibly indirectly) loading your library, you can use the fact that python runs a script under the name __main__. You can get it from sys.modules just like any other module and access its __file__ attribute if it exists:

import sys

try:
    print(sys.modules['__main__'].__file__)
except KeyError:
    print('libray not loaded from script')
except AttributeError:
    print('script not loaded from file')

The KeyError is unlikely to ever occur (not even if you run the script with python -m), but it's useful to be safe. The AttributeError is much more likely, and can easily be demonstrated with something like python -c.

If you want something more complex, like the file containing the code that actually called your library function, you will likely have to use the inspect module or similar. This will be even less robust as a matter of course, but may still suit your needs:

import inspect

module = inspect.getmodule(inspect.stack()[1][0])
try:
    print(module.__file__)
except AttributeError:
    print(f'module "{module.__name__}" not loaded from file')

Notice that inspect.getmodule explicitly uses the word "guess" in its official documentation, while inspect.stack can be a fidgety beast sometimes.

Code for second part referenced from here: https://stackoverflow.com/a/1095621/2988730.

Remember that there are two options here. If you place this code directly in your library module, it will be executed exactly once, when the module is first imported. If you place it in a function that the user can call directly, you will see the printouts every time. If you place the second snippet it in a utility function that you then call from your public module functions, don't forget to increment the frame index to reflect that:

module = inspect.getmodule(inspect.stack()[2][0])

Upvotes: 1

Related Questions