0

I want to import "main" from a subfolder. Therefore every subfolder contains a __init__.py (but not "source", and its actual name is "Tracks Comparer"). My folders structure is like this:

source\
  GPX\
    engine.py  (contains Engine class)
  main.py
    from GPX.engine import Engine
  Tests\
    Integration Tests\
      GPX\
        engineTest.py
      mainTest.py

I want use "main" from mainTest.py, so I tried:

from ... import main 

but it does'n work. Error: Attempted relative import in non-package

I use Visual Studio and with "Test Explorer" all tests run except for mainTest.py. For example in engineTest.py there is:

from GPX.engine import Engine

and not something like this:

from ...GPX.engine import Engine   # this not works

and in mainTest.py the simple import main works too.

To be more exact launching tests with Visual Studio works also for mainTest, BUT the import of Engine from GPX.engine fails (Error: engine module not found), I imagine because it refers to the GPX folder in the "Tests" folder. For these reasons, I think the unittest.run() is "called" from root (source folder) when Visual Studio launch tests.

To solve the problem I want to use relative paths (in tests files), but it doesn't work, as I said.

What's wrong in my relative path import? Is this the right way for doing the job? I'm using Python 2.7.


Solution for Attempted relative import in non-package: (in mainTest.py)

import os, sys
sys.path.append(os.path.join("..", ".."))
import main

Solution for engine module not found: (in mainTest.py)

#sys.path.append(os.path.join("..", ".."))
sys.path.insert(0, os.path.join("..", ".."))   
# <-- this change set "source" earlier than "Integration Tests" in path.
Alex 75
  • 2,798
  • 1
  • 31
  • 48

2 Answers2

1

Assuming you are currently in Integration Tests folder? What about this:

from os import path
import sys
currentDirectory = path.dirname(__file__)
sys.path.append(path.join(currentDirectory, '../../')) # This will get you to source
import main
Chrispresso
  • 3,660
  • 2
  • 19
  • 31
  • 1
    you could simplify that with `sys.path.append(os.path.join("..", ".."))`. More OS independent using os.path.join. Example **http://dbgr.cc/H** – nOOb cODEr Jun 18 '14 at 22:00
  • Very true. Yours is the one I would go with in the end. I just always use my example to show how it's derived. – Chrispresso Jun 18 '14 at 22:04
  • Yes. This is the solution for the "Attempted relative import in non-package" obtained by import main. Thanks. – Alex 75 Jun 19 '14 at 17:11
0

Relative imports don't work at the file system level, so what you want to do can't be done with relative imports as you described.

It sounds like you are having issues with implicit relative imports (in mainTest when you import GPX it implicitly imports .GPX instead of GPX as a root module). You can turn off this behavior by adding this line at the top of all your test files:

from __future__ import absolute_import

This will make python import GPX from sys.path instead of .GPX.

univerio
  • 19,548
  • 3
  • 66
  • 68
  • I've solved the first problem, import main. I've added the *absolute_import* from \__future\__ (in main.py, and then also in mainTest.py), but it still not works (engine is not found launching mainTest.py). – Alex 75 Jun 19 '14 at 17:22
  • 1
    @alex75 In that case, your `Integration Tests` directory is earlier in `sys.path` than your `source` directory. You need to modify the other solution to place it at the front: `sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))`. – univerio Jun 19 '14 at 17:39
  • Yes. This works. Changed "sys.path.append(os.path.join("..", ".."))" in "sys.path.insert(0, os.path.join("..", ".."))". Thanks. – Alex 75 Jun 19 '14 at 18:00