Question

I'm trying to determine the actual current module of a function (as seen if imported from elsewhere), even if the current module is the "top level scripting environment" __main__.

It may sound like a weird thing to do, but the background is that I need to serialize a function and unserialize it (including arguments) on a different machine, for which I need to make sure the correct module AND NOT __main__ is imported before deserializing (otherwise I get an error saying AttributeError: 'module' object has no attribute my_fun).

So far, I've tried inspection:

import inspect
print inspect.getmodule(my_fun)

which gives me

<module '__main__' from 'example.py'>

of course. I also tried finding something useful using globals(), no luck.

What I really want is <module 'example' from 'example.py'>. I suppose a hacky way would be to parse it from the file name using something like

m_name = __main__.__file__.split("/")[-1].replace(".pyc","")

and then find the module by name sys.modules[m_name].

Is there a cleaner/better way to do this?

EDIT: After learning about ipython's "FakeModule" and a bit more googling, I came accross this post, which describes exactly the problem that I'm facing, including my current solution to it (which is explicitly importing the current module import current_module and serializing current_module.my_fun instead of my_fun). I'm trying to avoid this, as it might not be intuitive for the users of my package.

Was it helpful?

Solution

I actually ran across this same problem.

What I used was:

return os.path.splitext(os.path.basename(__main__.__file__))[0]

Which is effectively the same as your "hack." Honestly, I think its the best solution.

OTHER TIPS

I know this is outdated but I found a simpler solution in Python3 that worked for me. Long story short, there's the object's __spec__ which also stores the actual module name instead of being "__main__".

import inspect
if obj.__class_.__module__ == "__main__":
    print(inspect.getmodule(obj).__spec__.name)

Edit: In retrospect, by far the best and cleanest solution is to avoid being in this situation in the first place; if it's your code that is being serialized, move all serializable functions to modules that are loaded by the main program script. This makes the origin of the function retrievable under any and all circumstances, without any need for hacks or special cases.

If that's not possible, I think your original solution (to retrieve the module name from __main__.__file__) is best and simplest. If you are worried about it seeming counter-intuitive for your users, wrap it in a nice function and document what it's for.

When you run a module as __main__, python really doesn't associate it with its normal module name: If you import example, it will load the file a second time as if it's a separate module. In fact this probably happens in your case, otherwise you wouldn't be able to find your module by name in sys.modules: Module example and module __main__ really are separate runtime objects, as you'll find out if you explicitly change a module variable in one of them.

One way you can do this -- possibly not the best way, but it works for me -- is to import your modules with __import__ and use getattr in a way something like the following.

(Here I am using some ideas described in this post about dynamically loading modules.)

def dynamic_import(name):
    mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

tmodule = dynamic_import('modA')
# Print the module name
print tmodule
# Use the module's contents
t = tmodule.myObject()
t.someMethod()

Where modA.py looks like this:

class myObject():
    def someMethod(self):
        print "I am module A"

So you can see we're getting the name of the module we've imported and still getting to use the objects and methods inside the module in a normal way. When I run this I get the following:

python experiment.py 
<module 'modA' from 'modA.pyc'>
I am module A

Again, this may or may not be the "ideal" way, but it works well and as far as I can tell doesn't entail any undesirable tradeoffs in most cases. Hope this helps.

I don't think any of the existing answers actually answer the question directly: how do you get the name of a module when it is run as __main__ ?

using inspect for most of the steps...

import inspect

def module_name(obj):
    module_name = obj.__module__

    if "__main__" in module_name:
        # get parent modules of object
        mod_obj = inspect.getmodule(obj) # type: module

        # from the filename of the module, get its name
        mod_suffix  = inspect.getmodulename(inspect.getmodule(obj).__file__)

        # join parent to child with a .
        module_name = '.'.join([mod_obj.__package__, mod_suffix])

    return module_name

As of python 3.4,

importlib.util.find_spec('__main__').name
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top