5

I want to import a class from a python file in a directory in the parent directory. This is my current folder structure:

│   run_simulation_from_parent.py
│   __init__.py
│
├───.vscode
│       launch.json
│       settings.json
│
├───mod
│   │   mods.py
│   │   __init__.py
│   │
│   └───__pycache__
│           __init__.cpython-37.pyc
│
├───sim
│   │   run_simulation.py
│   │   __init__.py
│   │
│   └───__pycache__
│           __init__.cpython-37.pyc
│
└───__pycache__
        __init__.cpython-37.pyc

The file mod/mods.py contains the following class:

class Objective:
    """Objective function class"""

    def __init__(self, x):
        self.x = x

The file sim/run_simulation.py contains:

from mod.mods import Objective

x = 5
obj = Objective(x)

When I try to run this I get the following error:

  File "sim/run_simulation.py", line 1, in <module>
    from mod.mods import Objective
ModuleNotFoundError: No module named 'mod'

In visual studio code it does autofill when I start typing mod.mods and import Objective

When I run run_simulation_from_parent.py with the following content I have no problems:

from mod.mods import Objective

x = 5
obj = Objective(x)

print(obj.x)

How can I do this from the directory sim? I already tried the following:

  1. Use from ..mod.mods import Objective to run_simulation.py
  2. Use init.py files with the following content: import os, sys sys.path.append(os.path.dirname(os.path.realpath(__file__)))

  3. Without the __init__.py files

Edit: I run the file from visual studio code where I start in the parent directory. I also tried from the command line in windows from the sim folder where I used

python run_simulation.py
user3223765
  • 99
  • 1
  • 8
  • Possible duplicate of [Import a file from a subdirectory?](https://stackoverflow.com/questions/1260792/import-a-file-from-a-subdirectory) –  Jun 28 '19 at 12:09
  • @user3223765 can you tell the way you are using the project, ie from where you are running the run_simulations.py file ? means how you are running it in terminal – sahasrara62 Jun 28 '19 at 13:39
  • I run the file from visual studio code where I start in the parent directory. – user3223765 Jun 28 '19 at 15:34

3 Answers3

5

The way I deal with imports inside a project is to install the project in editable mode. This way, all files will be able to locate each other, always starting from your project root directory.

In order to do this, follow these steps:

1) write a setup.py file and add it to your project root folder - it doesn't need much info at all:

# setup.py
from setuptools import setup, find_packages

setup(name='MyPackageName', version='1.0.0', packages=find_packages())

2) install your package in editable mode (ideally from a virtual environment). From a terminal in your project folder, write

$ pip install -e .

Note the dot - this means "install the package from the current directory in editable mode".

3) your files inside the project are now able to locate each other, always starting from the project root. To import Objective, for example, you write:

from mod.mods import Objective

This will be true to import Objective for any file, no matter where it is located in the project structure.

Like I said, you should use a virtual environment for this, so that pip does not install your package to your main Python installation (which could be messy if your project has many dependencies).

My favorite tool for this is pipenv. When using it, replace the terminal command with

$ pipenv install -e .

So that your project gets added to the Pipfile.

jfaccioni
  • 7,099
  • 1
  • 9
  • 25
  • Thanks for you elaborate explanation! I tried what you said and used 'setup(name='Objective', version='1.0.0', packages=find_packages())' I ran the pip command and a folder called Objective.egg-info is created. It doesn't solve my problem though.. – user3223765 Jun 28 '19 at 12:28
1

Use from ..mod.mods import Objective and keep all the __init__.py files.

fgoudra
  • 751
  • 8
  • 23
1

I did find one solution by adding it to the system path:

import os
import os.path
import sys

sys.path.append(os.getcwd() + "\\mod")

from mods import Objective

x = 5
obj = Objective(x)

print(obj.x)

This works but I cannot imagine that this is really how it is intended..

Edit: The following is a bit more general:

import os
import sys

sys.path.append(os.getcwd())

from mod.mods import Objective

x = 5
obj = Objective(x)

print(obj.x)

Something tells me that this could be done easier but I don't know how..

user3223765
  • 99
  • 1
  • 8