10

I'm curious if it's possible to access the name of the parent module that some other module is imported into.

For instance, if I have a module (moduleA) and a parent is module, foo.py, into which it will be imported into, is it possible for moduleA to know where foo is located ?

ModuleA

def print_parent_module(): 
    os.path.asbpath(#somehow access filename of parent module) 

foo.py

import moduleA 

print moduleA.print_parent_module()
>>> "foo.py"
Zack Yoshyaro
  • 2,056
  • 6
  • 24
  • 46
  • A module can be imported into many other modules, so there is no such thing as "the" module that imports it. – BrenBarn Sep 22 '13 at 20:06
  • 1
    I think he means to ask whether you can write a function that recognizes the file name that is importing it (from an external module) – yuvi Sep 22 '13 at 20:10
  • @yuvi Yeah! I explained it poorly, but that's what I'm asking. – Zack Yoshyaro Sep 22 '13 at 20:11
  • 1
    Possible, yes. A good idea? Certainly not. If you're asking with the intent to actually do it, don't. –  Sep 22 '13 at 20:12
  • @ZackYoshyaro try using the builtin [`__file__`](http://stackoverflow.com/questions/2632199/how-do-i-get-the-path-of-the-current-executed-file-in-python) magic method to get the name of the current file. As in, `os.path.abspath(__file__)`. – yurisich Sep 22 '13 at 20:13
  • @Droogans Tired that one. Unfortunately it gives the path to the module in which it is written, not the module it's imported into. – Zack Yoshyaro Sep 22 '13 at 20:17
  • @delnan I learn best from mistakes ;) Care to explain how it is done (even though you don't recommend it?) – Zack Yoshyaro Sep 22 '13 at 20:19
  • I can't be bothered to look up the details necessary for a full answer, but basically you inspect the call stack (at module level, not inside `print_parent_module`). –  Sep 22 '13 at 20:42
  • The more general question you're asking already has an answer, see https://stackoverflow.com/questions/7150998/where-is-module-being-imported-from and related answers. You need to use inspect lib. – Brian Peterson Dec 30 '17 at 22:00

4 Answers4

7

I ran into a similar issue. You could make use of __name__:

parent_name = '.'.join(__name__.split('.')[:-1])

Or if you try to access the module directly (not the OP's question but related), see my answer in Is there a way to access parent modules in Python

Dorian B.
  • 1,101
  • 13
  • 22
  • I needed this answer. I was trying to make a root logger for my application in one module in a directory, and have all loggers in that directory propagate up to it. It wasn't working because its module name was too specific, thus I needed the parent directory of the module. – Brian Peterson Dec 30 '17 at 21:59
  • Use rsplit for (slightly) faster code and certainly more readable. I wouldn't count on it being faster in a benchmark though, who knows – Hack5 Sep 23 '19 at 15:23
  • 1
    slightly shorter ways: `parent_name = __name__.rsplit('.', 1)[0]`, and `parent_name = __name__.rpartition('.')[0]` – Javier TG Dec 27 '22 at 18:08
1

No. Imported modules do not hold any form of state which stores data related to how they are imported.

I think the better question is, why would you even want to do it this way? You're aware that if foo.py is indeed your __main__ then you can easily get the name foo.py out of it (by using sys.argv)? And if foo.py is an imported module instead, then you obviously already know the name of foo.py and its location, etc. at the time that you import it.

Shashank
  • 13,713
  • 5
  • 37
  • 63
  • It seems a little convoluted, I'm sure, but the reason for wanting to do it this way is for decorating a main func in a way that the client code doesn't need to pass any args to the decorator. I figured out a simple work around (posted it as an answer below). – Zack Yoshyaro Sep 22 '13 at 20:28
0

Here is something I came with to store a parent's method name and variables to be recalled later in the class with a decorator.

import inspect
from functools import wraps

def set_reuse_vars(method):
    @wraps(method)
    def _impl(self, *method_args, **method_kwargs):
        func_current = inspect.currentframe()
        self.recall_func = dict()
        self.recall_func['method_kwargs'] = func_current.f_locals['method_kwargs']
        self.recall_func['method_name'] = func_current.f_locals['method'].__name__
        return method(self, *method_args, **method_kwargs)
    return _impl

class APIData(object):

    def __init__(self):
        self.client = None
        self.response = None
        self.recall_func = None

    def get_next_page(self):
        # Takes a pageToken to return the next result
        get_func = getattr(self, self.recall_func['method_name'])
        self.recall_func['method_kwargs']['pageToken'] = self.response['nextPageToken']
        return get_func(**self.recall_func['method_kwargs'])

    @set_reuse_vars
    def search_list_by_keyword(self, **kwargs):

        self.response = self.client.search().list(
            **kwargs
        ).execute()

        return self.response

script to run it.

api_data = APIData()


results = api_data.search_list_by_keyword(
                       part='snippet',
                       maxResults=25,
                       order='date')


print(results)

resultsTwo = api_data.get_next_page()

print(resultsTwo)
jmcgrath207
  • 1,317
  • 2
  • 19
  • 31
-2

Figured it out!

A little import statement inside of the function can give access to the module name.

moduleA

def print_module_name():
    import sys
    return sys.argv[0]

Then, inside the "parent" module

# foo.py
import os 
import moduleA

if __name__ == '__main__':
    print os.path.split(moduleA.print_module_name())[-1]

Gives:

>>> 'foo.py'
Community
  • 1
  • 1
Zack Yoshyaro
  • 2,056
  • 6
  • 24
  • 46
  • This is just printing the name of the script you're running. It has nothing to do with imports. – Ismail Badawi Sep 22 '13 at 20:29
  • @IsmailBadawi Well.. That was what my question was. How to get the parent module that another module was imported into. This does that. I'm thinking I just explained what I was trying to accomplish very poorly.. :/ – Zack Yoshyaro Sep 22 '13 at 20:36
  • 2
    But that's not what this is doing. This is printing the name of the script you're running. If you run foo.py, and it imports A, and A imports B, then `B.print_module_name()` will return foo.py, not A. – Ismail Badawi Sep 22 '13 at 20:37
  • 3
    Conceivably this is the solution to your problem. However, it's not the answer to the question you asked. – David Heffernan Sep 22 '13 at 20:46
  • 1
    @IsmailBadawi, Ohhh... I see what you're saying now. My apologies. Yeah, I explained my question quite poorly it seems! By "module name," I guess I meant "name of the script that's calling the imported function." – Zack Yoshyaro Sep 22 '13 at 20:54
  • @DavidHeffernan yeah, that seems to be the concensus. I'll edit or delete when I get back to a proper computer. – Zack Yoshyaro Sep 22 '13 at 21:00