简体   繁体   中英

Python imports when scripts are run from different folder (ancestor)

I have a large repository with some fixed structure and I have extended it by some folders and python scripts to add extra functionality to it as a whole. The structure looks as follows:

  • toplevelfolder
    • featureA
      • someModuleA.py
      • __ init __.py
    • featureB
      • someModuleB.py
      • __ init __.py
    • application
    • __ init __.py
    • app.py

Now someModuleA.py and someModuleB.py can be invoked via app.py but at the same time also have be able to be invoked directly, however this invocation must come from the toplevelfolder for the relative paths in the file to resolve correctly, ie via python./featureA/someModuleA.py .

This all works well, but now I need some function definitions from someModuleB in someModuleA and hence I want to import this module. I have tried both absolute and relative imports, but both fail with different errors, the absolute import with

from toplevelfolder.featureA import someModuleA as A

# ModuleNotFoundError: No module named 'toplevelfolder'

and the relative import with

from toplevelfolder.featureA import someModuleA as A

# ImportError: attempted relative import with no known parent package

Now I can see that the relative import would cause problems when python is invoked from the toplevelfolder , as .. would represent the latter's parent directory, rather than the parent directory of featureA . However, I cannot get a hold of the first error message, especially since toplevelfolder should not be a module but a package.

Is there another way to import in Python that I'm not aware of, if possibly without modifying PYTHONPATH or sys.path or something like that?

Not 100% sure on what the goal is here. My advice would be:

  1. Identify clearly what you want your top level modules and packages to be.

  2. Make all imports absolute.

  3. Either:

    • make your project a real installable project, so that those top level modules and packages are installed in the environment's site-packages directory;
    • or make sure that the current working directory is the one containing the top level modules and packages.
  4. Make sure to call your code via the executable module or package method instead of the script method, if the " entry point " you want to execute is part of a package

    • DO ( executable module or package ):
      • path/to/pythonX.Y -m toplevelpackage.module
      • path/to/pythonX.Y -m toplevelpackage.subpackage (assuming there is a toplevelpackage/subpackage/__main__.py file)
    • DON'T ( script within a package):
      • path/to/pythonX.Y toplevelpackage/module.py
  5. (Optional) Later on, once it all works well and everything is under control, you might decide to change some or all imports to relative. (If things are done right, I believe it could be possible to make it so that it is possible to call the executable modules from any level within the directory structure as the current working directory.)

References:

Don't include the top level directory. In featureB.someModuleB:

from featureA.someModuleA import two

Sample directory.

Try pasting this above your import:

import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir) 

Then you should be able to import a file from the parent-folder.

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