13

Given a frame object, I need to get the corresponding module object. In other words, implement callers_module so this works:

import sys
from some_other_module import callers_module
assert sys.modules[__name__] is callers_module()

(That would be equivalent because I can generate a stack trace in the function for this test case. The imports are there simply to make that example complete and testable, and prevent callers_module from taking the shortcut of using __name__, since it's in a different module.)

I've attempted this:

import inspect
def callers_module():
  return inspect.currentframe().f_back

Which gets a frame object, on which f_code will give me a code object, but I can't find out how to get the corresponding module or its name (to use with sys.modules). If I could get function objects, those have a __module__ attribute (and also have code objects), but that's not present in the frame. Indeed, not all code objects belong to function objects, such as the code for my test case (with assert, above). The same can be said of frame/code objects not having a module—but many of them do, and in my case they will, so that doesn't need to be handled; however, a simple None or exception is fine in that case, too.

It feels like I'm missing something simple. What needs to be done for this to work?

2 Answers2

15

While inspect.getmodule works great, and I was indeed looking in the wrong place to find it, I found a slightly better solution for me:

def callers_module():
  module_name = inspect.currentframe().f_back.f_globals["__name__"]
  return sys.modules[module_name]

It still uses inspect.currentframe (which I prefer over the exactly identical sys._getframe), but doesn't invoke inspect's module-filename mapping (in inspect.getmodule).

Additionally, this question inspired an interesting way to manage __all__:

from export import export

@export
class Example: pass

@export
def example: pass

answer = 42
export.name("answer")

assert __all__ == ["Example", "example", "answer"]
  • Now I wish I could make modules callable and simplify the above example: http://stackoverflow.com/questions/1060796/callable-modules –  Jan 09 '10 at 07:18
  • 5
    Beware if you're looking for the string with the module name. It won't work as expected if the module is executed as a [top-level script](https://docs.python.org/3/library/__main__.html), because then ``__name__`` will be always ``__main__``. To cover all cases, it's best to use ``inspect.getmodule().__spec__.name`` which will bring the real module's name even it is the top-level script. – Lucio Paiva Jan 08 '15 at 13:51
7
import inspect
def callers_module():
   module = inspect.getmodule(inspect.currentframe().f_back)
   return module
manifest
  • 2,208
  • 16
  • 13