Question

I know this does not sound Pythonic, but bear with me for a second.

I am writing a module that depends on some external closed-source module. That module needs to get instantiated to be used (using module.create()).

My module attempts to figure out if my user already loaded that module (easy to do), but then needs to figure out if the module was instantiated. I understand that checking out the type() of each variable can tell me this, but I am not sure how I can get the names of variables defined by the main program. The reason for this is that when one instantiates the model, they also set a bunch of parameters that I do not want to overwrite for any reason.

My attempts so far involved using sys._getframe().f_globals and iterating through the elements, but in my testing it doesn't work. If I instantiate the module as modInst and then call the function in my module, it fails to show the modInst variable. Is there another solution to this? Sample code provided below.

import sys
if moduleName not in sys.modules:
    import moduleName
    modInst = moduleName.create()
else:
    globalVars = sys._getframe().f_globals
    for key, value in globalVars:
        if value == "Module Name Instance":
            return key
    return moduleName.create()

EDIT: Sample code included.

Was it helpful?

Solution

Looks like your code assumes that the .create() function was called, if at all, by the immediate/direct caller of your function (which you show only partially, making it pretty hard to be sure about what's going on) and the results placed in a global variable (of the module where the caller of your function resides). It all seems pretty fragile. Doesn't that third-party module have some global variables of its own that are affected by whether the module's create has been called or not? I imagine it would -- where else is it keeping the state-changes resulting from executing the create -- and I would explore that.

To address a specific issue you raise,

I am not sure how I can get the names of variables defined by the main program

that's easy -- the main program is found, as a module, in sys.modules['__main__'], so just use vars(sys.modules['__main__']) to get the global dictionary of the main program (the variable names are the keys in that dictionary, along of course with names of functions, classes, etc -- the module, like any other module, has exactly one top-level/global namespace, not one for variables, a separate one for functions, etc).

OTHER TIPS

Suppose the external closed-sourced module is called extmod. Create my_extmod.py:

import extmod
INSTANTIATED=False
def create(*args,**kw):
    global INSTANTIATED
    INSTANTIATED=True
    return extmod.create(*args,**kw)

Then require your users to import my_extmod instead of extmod directly. To test if the create function has been called, just check the value of extmod.INSTANTIATED.

Edit: If you open up an IPython session and type import extmod, then type extmod.[TAB], then you'll see all the top-level variables in the extmod namespace. This might help you find some parameter that changes when extmod.create is called.

Barring that, and barring the possibility of training users to import my_extmod, then perhaps you could use something like the function below. find_extmod_instance searches through all modules in sys.modules.

def find_instance(cls):
    for modname in sys.modules:
        module=sys.modules[modname]
        for value in vars(module).values():
            if isinstance(value,cls):
                return value

x=find_instance(extmod.ExtmodClass) or extmod.create()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top