0

I have a problem with my Python project. My project parses different recipe websites for each recipe and writes the recipe data to a text file.

My Problem: I cannot import a python file/module that resides in the parent directory. This file contains generic functions that parse webpages. I get an error when I do so: "ValueError: Attempted relative import in non-package"

My solution: I dont know what my solution is? I am thinking I either need to find a way to import a file from the parent directory or to change my project architecture so every domain parsing script sits in the same directory

Project Architecture:

Test Folder:  
    __init__.py   
    UtilityFunctions.py     # the file I am importing  
    PerformAllIndexing.py 
    all_recipes:
        __init__.py
        index.py            # imports ../UtilityFunctions.py
    simply_recipes:
       __init__.py
        index.py            # imports ../UtilityFunctions.py

Each subdirectory contains a file called index.py that can extract recipe name, ingredients and directions for a specific website and writes it to a text file.

I encourage you to download my project to get a detailed understanding of my problem: http://www.mediafire.com/?ynup22oe8ofam21

Can you tell me what I can do to import a python module from a parent directory or how I can change my project architecture to make this work without having repeating code(the code residing in UtilityFunctions.py)?

sazr
  • 24,984
  • 66
  • 194
  • 362
  • 1
    Thanks for the organized question. But can you please post what your import statement looks like? Not everyone want to download your whole project to find out. – jdi Mar 18 '12 at 05:35
  • You can refer to my answer in this [question][1]. I hope that helps. [1]: http://stackoverflow.com/questions/714063/python-importing-modules-from-parent-folder/9331002#9331002 – Ricardo Murillo Mar 18 '12 at 05:43

3 Answers3

2

Just add the Test Folder to the python sys.path so you can import it with no problems.

import sys
# Add the Test Folder path to the sys.path list
sys.path.append('/path/to/test/folder/')

# Now you can import your module
from test_folder import UtilityFunctions
Ricardo Murillo
  • 2,775
  • 1
  • 18
  • 12
  • And I believe the relative import should also work at that point: from .. import UtilityFunctions – jdi Mar 18 '12 at 05:48
  • to remove the path dependency you can append to sys path like sys.path.append(../Test_Folder) – thavan Mar 18 '12 at 06:19
1

I found that relative imports and project layout can be quite tricky to get the hang of! If you follow these steps you should get it working:

  • Firstly, if you're using python < 2.5 make sure you have from __future__ import relative_imports.
  • Then, to keep it simple you need this layout

    Project Root Folder:
        Test_Folder:  
            __init__.py   
            UtilityFunctions.py 
            PerformAllIndexing.py 
            all_recipes:
                __init__.py
                index.py
            simply_recipes:
                __init__.py
                index.py
    

    Note that there is no __init__ in Project Root Folder.

  • You then need to make sure that Project Root Folder is in your PYTHONPATH.
  • Now, relative imports inside your library should work fine, e.g. inside all_recipes.index:

    from .. import UtilityFunctions
    

    and absolute imports start at Test Folder, e.g.

    from Test_Folder import UtilityFunctions
    

This won't work, however, if you just try running all_recipes.index. When you run your script, it needs absolute imports. Think of it as if you are writing a library and a script which uses the library. The library uses relative imports, but you can't run it normally using python -m. You can run the script like this, but can't use relative imports. So your script could look something like

    from Test_Folder.PerformAllIndexing import run
    run()

This can result in problems when you try to run unit tests, since you don't always want to run the entire suite. My suggestion for tests is to keep the in a separate tests folder under Project Root Folder and only use absolute imports. Its also helps to use a test runner such as nose.

aquavitae
  • 17,414
  • 11
  • 63
  • 106
  • 1
    Relative imports have been available since python2.5. He would have to be on an old python to need that future import – jdi Mar 18 '12 at 05:53
  • Thanks for the info, I thought they were only included in python3... I'll update my answer. – aquavitae Mar 18 '12 at 06:02
0

Your project architecture:

Test Folder:  
    __init__.py   
    UtilityFunctions.py     # the file I am importing  
    PerformAllIndexing.py 
    all_recipes:
        __init__.py
        index.py            # imports ../UtilityFunctions.py
    simply_recipes:
       __init__.py
        index.py            # imports ../UtilityFunctions.py

To not fiddle with PYTHONPATH or sys.path, you better move all_recipes/index.py and simply_recipes/index.py to the root of your project, naming them accordingly.

Thus UtilityFunctions will readily available to you using import UtilityFunctions (btw, you should name it utility_functions).

See also: Import paths - the right way?

P.S. Altering sys.path sometimes can lead to strange behaviour. For example a module can be imported twice. Also you must set up your IDE to be aware of your modifications of the paths.

Community
  • 1
  • 1
warvariuc
  • 57,116
  • 41
  • 173
  • 227