0

I'm relatively new to Python and I need to make a script which can call a function from a file in parent folder. In simple terms, the directory now looks like this:

  • parentModule.py
  • childDirectory/
    - childScript.py

parentModule.py contains the following script

def runFunction():
    print('function triggered')
    return 1

childScript.py contains the following script

import sys, os

sys.path.append( os.path.dirname(os.path.realpath(__file__))+'/..')
import parentModule

def runChildMain():
    '''
    run runFunction from parentModule.py
    '''
    parentModule.runFunction()

    # Do stuff in childDirectory, for example, create an empty python file
    open('test', 'a').close()

runChildMain()

I need to be able to run childScript.py on its own because later on the childScript.py will be run as a subprocess. The problem is that when I use sys.path, which I did not mention before, the command to create a file with open() runs in the parent directory, not in the childDirectory. So, this results in the file 'test' created in the parentDirectory, but I need it to be created inside childDirectory.

  • https://stackoverflow.com/questions/67631/how-do-i-import-a-module-given-the-full-path?rq=1 – dtm Jul 05 '22 at 17:00
  • Why won't `sys.path` work? `sys.path.append( os.path.dirname(os.path.realpath(__file__))+'/..')`? – Tim Roberts Jul 05 '22 at 17:03
  • https://stackoverflow.com/questions/4383571/importing-files-from-different-folder – Arya Singh Jul 05 '22 at 17:11
  • @dtm can you try to elaborate that example with the scripts in the question? I have tried the accepted answer in that link but I still don't really understand how to use it, therefore I have errors – user19488694 Jul 05 '22 at 17:12

3 Answers3

0

I know it is possible to go down a directory ie:

parentModule.py:

from childDirectory.childScript import runChildMain
def runFunction():
    runChildMain()
runFunction()

childScript.py

def runChildMain():
    print("HIT Run child main")

if __name__ == "__main__":
    runChildMain()

if the file structure has to be set up that way though you may have to use:

sys.path.append( os.path.dirname(os.path.realpath(__file__))+'/..')
Trevor Hurst
  • 74
  • 10
  • I have updated my question and explained why the sys.path approach does not get me the result I wanted. Thanks for the solution though, might be useful for others who just needs to import modules from parent directory – user19488694 Jul 05 '22 at 17:26
0

So I have found the solution. Basically after importing the parent module, I need to change the working directory to the child directory in order to continue do stuff inside the child directory.

Code below is the answer for my question

# Import from parent directory -- https://stackoverflow.com/questions/67631/how-do-i-import-a-module-given-the-full-path?rq=1
import importlib.util
import sys, os
spec = importlib.util.spec_from_file_location("parentModule", "parentModule.py")
foo = importlib.util.module_from_spec(spec)
sys.modules["module.name"] = foo
spec.loader.exec_module(foo)

# Change working directory to child directory
os.chdir("childDir")

def runChildMain():
    foo.runFunction()

    # This will be executed in the child directory
    open('test2', 'a').close()

runChildMain()
0

The correct way of doing this is to run the script with the -m switch

python -m childDirectory.childScript # from the parent of childDirectory

Then in childScript you do a simple from parentModule import runFunction. Hacking the sys path is bad practice and using chdir should be also avoided (leads to nasty surprises)

Mr_and_Mrs_D
  • 32,208
  • 39
  • 178
  • 361
  • Hi, first of all, thanks a lot for the simplicity. Your solution almost 100% works. It's just that when I use ```from ..parentModule import runFunction``` I got the ```attempted relative import beyond top-level package``` error, but if I use ```from parentModule import runFunction``` it works. Is there something I'm missing or doing wrong? – user19488694 Jul 06 '22 at 18:30
  • @user19488694 no it's me who got it wrong let me edit :) – Mr_and_Mrs_D Jul 07 '22 at 12:35