简体   繁体   中英

Dynamic module imports from external function, (or - editing globals() outside of module), in Python

I have a project in which I want to repeatedly change code in a class and then run other modules to test the changes (verification..). Currently, after each edit I have to reload the code, the testing modules which run it, and then run the test. I want to reduce this cycle to one line, moreover, I will later want to test different classes, so I want to be able to receive the name of the tested class as a parameter - meaning I need dynamic imports.

I wrote a function for clean imports of any module, it seems to work:

def build_module_clean(module_string,attr_strings):
    module = import_module(module_string)
    module = reload(module)
    for f in attr_strings:
        globals()[f]=getattr(module,f)

Now, in the name of cleanliness, I want to keep this function in a wrapper module (which will contain the one-liner I want to rebuild and test all the code each time), and run it from the various modules, ie among the import statements of my ModelChecker module I would place the line

from wrapper import build_module_clean
build_module_clean('test_class_module',['test_class_name'])

however, when I do this, it seems the test class is added to the globals in the wrapper module, but not in the ModelChecker module (attempting to access globals()['test_class_name'] in ModelChecker gives a key error). I have tried passing globals or globals() as further parameters to build_module_clean , but globals is a function (so the test module is still loaded to the wrapper globals ), and passing and then using globals() gives the error

TypeError: 'builtin_function_or_method' object does not support item assignment

So I need some way to edit one module's globals() from another module.


Alternatively, (ideally?) I would like to import the test_class module in the wrapper, in a manner that would make it visible to all the modules that use it (eg ModelChecker ). How can I do that?

Your function should look like:

def build_module_clean(globals, module_string, attr_strings):
    module = import_module(module_string)
    module = reload(module)
    globals[module_string] = module
    for f in attr_strings:
        globals[f] = getattr(module, f)

and call it like so:

build_module_clean(globals(), 'test_class_module', ['test_class_name'])

Explanation:

Calling globals() in the function call ( build_module_clean(globals()... ) grabs the module's __dict__ while still in the correct module and passes that to your function.

The function is then able to (re)assign the names to the newly-loaded module and it's current attributes.

Note that I also (re)assigned the newly-loaded module itself to the globals (you may not want that part).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM