0

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.

8
  • Can you povide the implementation of import_module( ... ) and definition of sub? Commented Sep 24, 2018 at 10:59
  • @mangus: Updated in the question. Commented Sep 24, 2018 at 11:02
  • How do you determine if you need A/b.py or B/b.py ? If both directories A and B are in the sys.path, then b.py is ambiguous. Commented Sep 24, 2018 at 11:17
  • The folder and the file name are passed on as parameters to the function. Commented Sep 24, 2018 at 11:40
  • If you first append A and then B to sys.path, then import b, you will get A/b.py, because A was appended first. It is however possible wrap the append() in an if-statement: if some_condition : sys.append("A"), but appending both will yield an ambiguous b.py. I recommend not appending to sys.path but use python modules instead, as shown in my answer below. Commented Sep 24, 2018 at 12:14

2 Answers 2

1

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
Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.