DylanJaide
DylanJaide

Reputation: 395

Python: How to choose one of multiple scripts as a package to import into a main script, when located in different directories?

I have multiple projects that all need a common script (main.py), but I need them to have different functions available that are specific to each project. This means that when I run the script for use in Project A, I want to be able to import its configA.py, but to import configB.py when running it for Project B.

For example, say that within both configA.py and configB.py, there is a different definition of the same function foo(). My goal is to be able to run something along the lines of python3 main.py ../../ProjectA/Config/configA.py for Project A, and similar for B. Then inside main.py, the script would import the file passed to it (something like config = import_module(sys.argv[0])), and then be able to run config.foo(), which would behave differently depending on which file was passed.

From reading a number of help posts on SO, I've seen many people suggest importlib.import_module(), since I can pass the package name as an argument to main.py. But the slight complication compared to these other posts I've read is to do with my file structure. It seems like import_module() only really works when the the main/package files are in the same directory, or when the main script is in a parent directory of the package. However, my file structure looks like this:

└─ Documents
   ├─ Common
   │  └─ Scripts
   │     └─ main.py
   ├─ ProjectA
   │  └─ Config
   │     └─ configA.py
   └─ ProjectB
      └─ Config
         └─ configB.py

Is there a way for me to be able to import the package of my choice for use in main.py given this file structure?

Upvotes: 1

Views: 228

Answers (1)

a_guest
a_guest

Reputation: 36249

You can use an if statement for the different imports:

import os
import sys

sys.path.insert(0, os.abspath('../..'))  # this is important so the packages are on the path

if sys.argv[1] == 'A':
    from ProjectA.Config.configA import foo
elif sys.argv[1] == 'B':
    from ProjectB.Config.configB import foo
else:
    raise ImportError(f'No module corresponding to {sys.argv[1]}')

Or you can use also use importlib.import_module instead of the if/else chain:

import importlib

module = importlib.import_module('Project{x}.Config.config{x}'.format(x=sys.argv[1]))
foo = module.foo

And then use via

python main.py A  # use foo from configA
python main.py B  # use foo from ConfigB

Run via -m from Documents

An alternative to modifying sys.path is to run the main.py via the -m switch from within the Documents directory. When running python main.py then the script's directory will be put on the path. When running python -m Common.Scripts.main then the current working directory will be put on the path and hence ProjectA and ProjectB are automatically discoverable:

$ pwd
/path/to/Documents
$ python -m Common.Scripts.main

Upvotes: 1

Related Questions