Solar
Solar

Reputation: 455

Use __init__.py to modify sys path is a good idea?

I want to ask you something that came to my mind doing some stuff.

I have the following structure:

src
    - __init__.py
    - class1.py
    + folder2
        - __init__.py
        - class2.py

I class2.py I want to import class1 to use it. Obviously, I cannot use

from src.class1 import Class1

cause it will produce an error. A workaround that works to me is to define the following in the __init__.py inside folder2:

import sys
sys.path.append('src')

My question is if this option is valid and a good idea to use or maybe there are better solutions.

Another question. Imagine that the project structure is:

src
    - __init__.py
    - class1.py
    + folder2
        - __init__.py
        - class2.py
    + errorsFolder
        - __init__.py
        - errors.py

In class1:

from errorsFolder.errors import Errors

this works fine. But if I try to do in class2 which is at the same level than errorsFolder:

from src.errorsFolder.errors import Errors

It fails (ImportError: No module named src.errorsFolder.errors)

Thank you in advance!

Upvotes: 8

Views: 13980

Answers (5)

Amos Baker
Amos Baker

Reputation: 839

There is also a solution that does not involve the use of the environment variable PYTHONPATH.

In src/ create setup.py with these contents:

from setuptools import setup
setup()

Now you can do pip install -e /path/to/src and import to your hearts content.

-e, --editable <path/url>   Install a project in editable mode (i.e. setuptools "develop mode") from a local project path or a VCS url.

Upvotes: 3

Jean-Fran&#231;ois Fabre
Jean-Fran&#231;ois Fabre

Reputation: 140148

Despite the fact that it's slightly shocking to have to import a "parent" module in your package, your workaround depends on the current directory you're running your application, which is bad.

import sys
sys.path.append('src')

should be

import sys,os
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),os.pardir))

to add the parent directory of the directory of your current module, regardless of the current directory you're running your application from (your module may be imported by several applications, which don't all require to be run in the same directory)

Upvotes: 4

bruno desthuilliers
bruno desthuilliers

Reputation: 77902

from ..class1 import Class1 should work (at least it does here in a similar layout, using python 2.7.x).

As a general rule: messing with sys.path is usually a very bad idea, specially if this allows a same module to be imported from two different paths (which would be the case with your files layout).

Also, you may want to think twice about your current layout. Python is not Java and doesn't require (nor even encourage) a "one class per module" approach. If both classes need to work together, they might be better in a same module, or at least in modules at the same level in the package tree (note that you can use the top-level package's __init__ as a facade to provide direct access to objects defined in submodules / subpackages). NB : I'm not saying that your current layout is necessarily wrong, just that it might not be the simplest one.

Upvotes: 1

Dev Batwada
Dev Batwada

Reputation: 49

No, Its not good. Python takes modules in two ways:

  1. Python looks for its modules and packages in $PYTHONPATH. Refer: https://docs.python.org/2/using/cmdline.html#envvar-PYTHONPATH

To find out what is included in $PYTHONPATH, run the following code in python (3):

import sys print(sys.path)

  1. all folder containing init.py are marked as python package.(if they are subdirectories under PYTHONPATH)

By help of these two ways you can full-fill the need to create a python project.

Upvotes: -1

John Zwinck
John Zwinck

Reputation: 249103

One correct way to solve this is to set the environment variable PYTHONPATH to the path which contains src. Then import src.class1 will always work, regardless of which directory you start in.

Upvotes: 3

Related Questions