6

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
  • 1
    Could you pass it as a parameter to bar.func(other_file) or is that cheating? Commented Jul 23, 2018 at 21:57
  • 1
    The standard inspect module 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... Commented Jul 23, 2018 at 21:57
  • Of course foo.py might be in an egg or a zipped lib, or there might be a foo.pyc but no foo.py, or foo might even be created by custom importlib code, or … What do you want to happen in those cases? (The inspect module can sometimes do some nifty tricks to get the source code even when the file isn’t directly available, if that’s what you’re interested in.) Commented Jul 23, 2018 at 22:06

3 Answers 3

7

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().

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

3 Comments

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.
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?
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.
1

In func, you can use inspect:

def func():
    stack = inspect.stack()
    calling_context = next(context for context in stack if context.filename != __file__)
    print(calling_context.filename)

Edited: I just saw jasonharper's comment that proposes the same solution. Read also abarnet's comment.

Comments

0

To get the absolute path, you can also try this:

import os
print(os.path.abspath("foo.py"))

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.