Reputation: 6220
I have the following file structure:
A:
|_ a.py
|_ b.py
B:
|_ a.py
|_ b.py
I want to dynamically execute either A/b.py or B/b.py.
I am using the following code:
from importlib import import_module
path = '/home/username/test/' + module + '/'
if path not in sys.path:
sys.path.append(path)
script = import_module('b', 'Script')
myClass = getattr(script, 'Script')
run = myClass()
Doing this, if I run B/b.py and then A/b.py, it will execute B/b.py instead of A/b.py.
The first script to be run will be executed in the next round.
I need help in making sure the file in the directory I want is run only.
Upvotes: 0
Views: 1081
Reputation: 1295
I've read your other, similar question and come up with a solution without any pre-imports. This is (imho) highly un-pythonic, and may by all means be considered a dirty "hack". I highly recommend you to consider my other answer and just properly deal with the imports.
Your problem occurs because you're trashing the namespace, and all it holds dear. When you pollute the namespace with functions/methods with the same signature, there is absolutely no way for the Python-interpreter to distinguish them: it resolves to the one that was first imported.
However, as stated, there is a workaround: There is (currently) no way to unload a python module, but you may reload
it, using the imp
module. Essentially, it lets you clean up (redefine) the namespace. A complete, working example can be found at my repl.it
# root_folder/main.py
import sys
import imp
from importlib import import_module
def import_script(mod_dir, script):
sys.path.append(mod_dir)
mod = imp.reload(import_module(script, 'Script'))
sys.path.remove(mod_dir)
return mod
# input:
mod_dir = "A"
script = "b"
# import module/script.py
active_mod = import_script(mod_dir, script)
# use module/script.py
mod_name = active_mod.get_mod_name()
print(mod_name) # Prints "A : b.y"
# New input: different module/script.py
mod_dir = "C"
script = "b"
# import module/script.py
active_mod = import_script(mod_dir, script)
# use module/script.py
mod_name = active_mod.get_mod_name()
print(mod_name) # Prints "C : b.y"
when the modules look like below,
# root_folder/A/b.py
def get_mod_name():
return "A : b.py"
Do note that every import is doubled, since everytime you import a module (with possibly a duplicate name), it must also be reloaded to clean up the namespace. It is not enough to just del
the module.
Upvotes: 0
Reputation: 1295
I'm making some assumption on what you want to accomplish here. Even if this is not exactly what you want, it might still push you the right direction: You got two different sub directories, A and B. These contain scripts of identical names a.py and b.py. Based on some condition, your script should call either A/a.py or A/a.py and then maybe B/b.py or B/b.py.
I would set up A and B as actual python modules, that is, create a __init__.py file in both folders. Then have a master-script which somehow determines which module to use..
# root_folder/master.py
import sys
import A
import B
master_script_name = sys.argv[0]
print("I'm the master script : " + str(master_script_name))
def choose_module_A_or_B(arg):
if arg == "A":
print(" You chose module A !")
return A
return B
module = choose_module_A_or_B("A")
module.b.print_locations()
Then,
# root_folder/A/__init__.py
from A import b
and,
# root_folder/A/b.py
import os
import sys
# how to obtain paths and script name:
folder = os.path.dirname(os.path.realpath(__file__))
script = __file__
parent = os.path.abspath(os.path.join(folder, os.pardir))
def print_locations():
print(" --> script : " + str(script))
print(" --> folder : " + str(folder))
print(" --> parent : " + str(parent))
Similarily ..
# root_folder/B/__init__.py
from B import b
and,
# root_folder/B/b.py
import os
import sys
# how to obtain paths and script name:
folder = os.path.dirname(os.path.realpath(__file__))
script = __file__
parent = os.path.abspath(os.path.join(folder, os.pardir))
def print_locations():
print(" --> script : " + str(script))
print(" --> folder : " + str(folder))
print(" --> parent : " + str(parent))
OUTPUT:
$ python master.py
I'm the master script : master.py
You chose module A !
--> script : A\b.py
--> folder : C:\dev\ScriptTesting\py\script_by_name\A
--> parent : C:\dev\ScriptTesting\py\script_by_name
Upvotes: 1