Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Import python packages that have similar internal module names, by full path

In my project I need to import two external packages from two different full paths.

When I had only one external package, I added its path to sys.path and it worked, I could do that for both of the package but unfortunately both packages have similar internal modules, so if I add them both to sys.path they will cross import internal modules from each other.

To clarify, the folder structure of the packages looks like this:

package1\
  __init__.py
  settings.py
  a.py # does 'import settings'

package2\
  __init__.py
  settings.py
  b.py # also does 'import settings'

How can I import both packages without conflicts? I've tried using imp.load_source but it looks like it can only load files.

Edit: When I only had one package, I would import from it using the following code:

sys.path.insert(1, "PATH TO PACKAGE1")
from package1 import a

Edit 2: The directory structure of the packages is actually much more complicated than the one in the one above, and contains hundreds of files. There are also internal modules that may import settings.py, for example:

package1\
  __init__.py
  settings.py
  internal_module\
    __init__.py
    a.py # does 'import settings'

This means I can't assume that a.py and settings.py are in the same directory.

like image 376
Tzach Avatar asked Nov 10 '22 15:11

Tzach


1 Answers

if you import settings in package1/a.py, python will look for settings.py first in the current director i.e package1 and not package2 even if they both are in sys.path. So even if you import as (based on the directory structure you have shown above) assuming you have added pacakge1 and package2 in sys.path:

from package1 import a
from package2 import b

This is going to work without any problem and a.py will import setttings module from package1 and b.py will import the settings from package2.

If you have modules with same name both in package1 and package2, then the good way to do the imports is

import package1.settings as package1_settings
import package2.settings as package2_settings

Now you can access your variables in package1_settings and package2_settings as

package1_settings.var1
package2_settings.var1

All this will work if you have added the absolute path to "package1" and "package2" to sys.path:

sys.path.append(os.path.abspath("package1")) # something like that

Here is a little experiment I did:

The package structure is:

package1
    __init__.py
    a.py
    settings.py

package2
    __init__.py
    b.py
    settings.py

test.py

a.py

import settings

def print_a():
    print settings.a

b.py

import settings

def print_a():
    print settings.a

package1.settings.py

a = "settings.py in package1"

package2.settings.py

a = "settings.py in package2"

test.py

import sys
import os

dir_name = os.path.abspath(os.path.dirname("__file__"))
package1_path = os.path.join(dir_name, "package1")
package2_path = os.path.join(dir_name, "package2")

sys.path.append(package1_path)
sys.path.append(package2_path)

from package1 import a
from package2 import b

a.print_a()
b.print_a()

Output of "python test.py"

>>> python test.py
settings.py in package1
settings.py in package2

Edit For such cases, the good practice is

Always reference your imports from your top level package

You will add package1 and package2 to your sys.path and reference all your imports from them.

import package1.settings as package1_settings
import package1.internal_module.a as package1_internal_module_a #give a shorter name
import package1.internal_module.other_module.settings as package1_internal_other_settings

This way it can be ensured that your import paths never collide with each other. One other advantage of this is portability of your package. Tomorrow if you decide to change the location of package1, all the code in your package1 would just work because all your imports are referenced from package1.

like image 103
praveen Avatar answered Nov 15 '22 06:11

praveen