Say I have two files, foo.py and bar.py. It does not matter where they are located, only that foo.py somehow manages to import bar.py and call a function func() defined in the latter. How would I get the absolute path of foo.py from bar.func()?
3 Answers
I'm not sure what you mean by "get the absolute path of foo.py from bar.func()". However, it's possible for a function to determine whose calling it at runtime by using sys._getframe() to reach back through the call stack and examine the calling function's globals (the variable namespace in the code below). Here's an example showing how to do that:
foo.py
import bar
bar.func()
bar.py
from pprint import pprint
import sys
def func():
namespace = sys._getframe(1).f_globals # caller's globals
pprint(namespace)
print("caller's path:", namespace['__file__'])
Sample output:
{'__annotations__': {},
'__builtins__': <module 'builtins' (built-in)>,
'__cached__': None,
'__doc__': None,
'__file__': '\\Stack Overflow\\get-path-of-calling-script\\foo.py',
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0085A7D0>,
'__name__': '__main__',
'__package__': None,
'__spec__': None,
'bar': <module 'bar' from '\\Stack Overflow\\get-path-of-calling-script\\bar.py'>,
'sys': <module 'sys' (built-in)>}
caller's path: \Stack Overflow\get-path-of-calling-script\foo.py
See the '__file__' entry in the returned dictionary? It's the absolute path to the source file — foo.py — that contained the call made to bar.func().
3 Comments
bzrr
What else could "get the absolute path of foo.py from bar.func()" mean in the context of the question? Non-rethorical, I just want to know so that maybe I can rewrite the question in a clearer way.
martineau
bzzr: I wasn't sure if you meant when it was called (like my answer does) or perhaps determining it via some sort of static analysis. In other words, I didn't know how you wanted/expected to "get" the information. May I ask for what purpose you need/want this info?
bzrr
I wanted to be able to refer to the calling script's path (really, the path to the script containing the calling function) independently of where the script was located, but I have since realized that wasn't necessary.
bar.func(other_file)or is that cheating?inspectmodule has functions to examine the call stack; given the function that called you, you can get the module that contains it; modules have a__FILE__attribute...