15

What is the right way in Python to import a module from a directory one level up? The directory is a Python package with all these modules and I have a sub directory with code that needs these modules.

The following works just fine, but that is just a hack. I'd like a recommended / pythonic way.

import sys
sys.path.append("../")
from fruit import Fruit
print("OK")

The directory structure:

pkg1
   __init__.py  
   fruit.py  
   +sub_pkg
      __init__.py
      recipe.py

contents of fruit.py

class Fruit:
   def get_name(self):
       print("Fruit name")

contents of sub_pkg/recipe.py .. just a single import line:

from fruit import Fruit

When I run :

python recipe.py

it gives the following error.

Traceback (most recent call last):
  File "recipe.py", line 2, in <module>
    from fruit import Fruit
ImportError: No module named fruit

I also tried: from pkg1.fruit import Fruit , does not work. Also looked at other similar questions .. python -m recipe.py or python -m sub_pkg/recipe.py did not work.

Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188
stackjs
  • 443
  • 2
  • 6
  • 13
  • What about this answer: http://stackoverflow.com/questions/72852/how-to-do-relative-imports-in-python – Olexander Yermakov Sep 24 '15 at 17:33
  • What is the error you are getting for `from pkg1.fruit import Fruit`? – Forge Sep 24 '15 at 17:38
  • @Irit: `ImportError: No module named temp.fruit` – stackjs Sep 24 '15 at 17:44
  • You should add `pkg1` to your PYTHONPATH. – Forge Sep 24 '15 at 17:49
  • If you are installing your python packages in the proper place, you shouldn't need to import from a directory up. Upper imports are not a good idea in general, it shows bad program design. Setting the system path and then importing as usual is a better solution than relative imports as mentioned below, which break on python3. – NuclearPeon Sep 24 '15 at 17:56
  • @NuclearPeon: why do you think it is a bad design to import a module from top level package in to a sub package? if you have any links to examples that show why it is a bad design it will work as well. – stackjs Sep 24 '15 at 18:06
  • @IritMalka: you are right about adding pkg1 in my PYTHONPATH. It solved the problem withput any modifications. Wondering if this is the standard practice? – stackjs Sep 24 '15 at 18:28
  • @IritMalka, more I read it, including the pkg documentation, I believe adidng the pkg to the search path seems correct way. Can you write this as an answer so that I can accept it? – stackjs Sep 24 '15 at 18:32
  • @stackjs https://www.python.org/dev/peps/pep-0008/#id17 - this explains a bit on imports. Explicit relative imports are OK, implicit ones have been removed in python3. Mailing list on the topic: https://mail.python.org/pipermail/python-dev/2013-July/127404.html My biggest issue with relative imports is that it's not only more error prone (more potential for circular imports), it's harder to read more often than not (which goes against the "python way") and it **couples modules together** which is generally bad. http://www.hokstad.com/why-coupling-is-always-bad-cohesion-vs-coupling – NuclearPeon Sep 24 '15 at 18:57
  • @NuclearPeon: thanks for the link to the article. I agree about your comment on the relative imports. But let us assume you are not doing a relative import.. in such case,,would you consider importing (absolute import) pkg.module inside pkg.sub_pkg.module a bad practice? ..as I can imagine a test directory to be part of this sub_pkg which needs the modules from pkg. – stackjs Sep 24 '15 at 19:22

4 Answers4

11

In your main file recipe.py add pkg1 path to the PYTHONPATH

sys.path.append('/path/to/pkg1')

Or use a relative path

sys.path.append('../..')

This should allow importing pkg1 from any where in your program.

There is always the option of using relative imports as suggested here, I find using absolute imports more readable and less likely to lead to bugs. Also, in large projects using relative imports will have you constantly calculating path hierarchies while when using absolute imports, it's simple to know you always refer to one root directory.

About relative imports from PEP328 in Python 2.5:

Reading code which relies on relative imports is also less clear, because a reader may be confused about which module is intended to be used. Python users soon learned not to duplicate the names of standard library modules in the names of their packages’ submodules, but you can’t protect against having your submodule’s name being used for a new module added in a future version of Python.


Guido is suggesting using leading dots in relative imports to avoid ambiguous imports as described above, from PEP328 again:

Guido has Pronounced that relative imports will use leading dots. A single leading dot indicates a relative import, starting with the current package. Two or more leading dots give a relative import to the parent(s) of the current package, one level per dot after the first.

Forge
  • 6,538
  • 6
  • 44
  • 64
  • setting up PYTHONPATH worked and seems like an acceptable solution (adding the pkg to search path) based on documentation. I had already tried sys.path.append , but decided not to go that way – stackjs Sep 24 '15 at 19:23
  • I've been trying to fix this type of issue for 5+ hours now and your second solution worked. Thank you!! – bbennett36 Feb 19 '20 at 20:20
3

If you're having issues you can use the following also.

This imports from current directory

from . import something

this import from one directory above

from .. import fruit

Doc for relative path: https://docs.python.org/2/tutorial/modules.html#intra-package-references

RELATIVE PACKAGE ISSUE ValueError: Attempted relative import in non-package

For people having issues with the relative package. Here's your solution.

if __name__ == "__main__" and __package__ is None:
    __package__ = "expected.package.name"

Also the explanation, copied from another python docs

When the main module is specified by its filename, then the package attribute will be set to None . To allow relative imports when the module is executed directly, boilerplate similar to the following would be needed before the first relative import statement:

if __name__ == "__main__" and __package__ is None:
    __package__ = "expected.package.name

Note that this boilerplate is sufficient only if the top level package is already accessible via sys.path . Additional code that manipulates sys.path would be needed in order for direct execution to work without the top level package already being importable.

Doc for creating packages I'm not going to paste the content since it's rather long, but here's the section on the python docs for creating packages. https://docs.python.org/2/tutorial/modules.html#packages

One more docs on PYTHONPATH https://docs.python.org/2/using/cmdline.html#envvar-PYTHONPATH

AdriVelaz
  • 543
  • 4
  • 15
  • Almost at the same time!! – avenet Sep 24 '15 at 17:49
  • thanks.. if I do any of these, it results in `ValueError: Attempted relative import in non-package` . This is same error as Olexander pointed out in another question. But didn't understand the solution! – stackjs Sep 24 '15 at 17:51
  • You reference the doc. That's always more beneficial. – AdriVelaz Sep 24 '15 at 17:52
  • Does not work in python3. `SystemError: Parent module '' not loaded, cannot perform relative import` – NuclearPeon Sep 24 '15 at 17:53
  • Added the issue you're having regarding relative path as well – AdriVelaz Sep 24 '15 at 18:02
  • @AdriVelaz: In the example I have shown, I am not using `__name__ == "__main__"` in recipe.py. So confused now as why package name would be set to `None` Could you please give the example with the code I have written.. ? thanks – stackjs Sep 24 '15 at 18:19
  • @stackjs the python docs is a great research for how to create packages. https://docs.python.org/2/tutorial/modules.html#packages – AdriVelaz Sep 24 '15 at 18:28
  • @AdriVelaz: thanks for the link! the documentation talks about the search path for the module. I think the problem was with PYTHONPATH and it seems like a standard way to specify – stackjs Sep 24 '15 at 18:34
  • 1
    small correction "this import from one directory above" is only true if you're in a proper python package and the directory above is a proper python package. (i.e. everything has a __init__.py and is designed to be a python package). If you're just trying to get one level up on the general filesystem, you'll need to alter the paths python searches. – Jonathan Vanasco Sep 24 '15 at 18:44
1

You can use relative imports:

from ..fruit import Fruit
avenet
  • 2,894
  • 1
  • 19
  • 26
-1

Instead of using upper imports, have an entry point that you can call from the upper most level and have your imports relative to that entry point in your recipe.py file.

Ex:

pkg1/
   __init__.py  
   main.py
   fruit.py  
   +sub_pkg
      __init__.py
      recipe.py

Where main.py contains:

#!/usr/bin/env python3

import subpkg.recipe as recipe
import fruit

if __package__ is None and __name__ == "__main__":
    __package__ = "main"
    print()
    # Call recipe.py or fruit.py methods from here

And in recipe.py:

import fruit
# do stuff with fruit module, which is properly imported now

To run, call python3 main.py

NuclearPeon
  • 5,743
  • 4
  • 44
  • 52
  • It would be more beneficial to just address the package within the script. instead of creating a separate run script. This removes the possibility of a script running on it's on, which may not scale in some scenarios. – AdriVelaz Sep 24 '15 at 18:05
  • @AdriVelaz Address what package in which list? I need some context – NuclearPeon Sep 24 '15 at 18:06
  • `__package__ = "expected.package.name"` Using `if __name__ == "__main__":` on the script level Here are the docs as well. https://www.python.org/dev/peps/pep-0366/#proposed-change – AdriVelaz Sep 24 '15 at 18:08
  • Done, but aside from python correctness, it doesn't really add anything to address OP's question – NuclearPeon Sep 24 '15 at 18:28
  • On a script level it defines the context of the package. It answers the OP's question. It's done before any formal imports. – AdriVelaz Sep 24 '15 at 18:29
  • @AdriVelaz So if it answers the OP's question, why are you using the default webpage example `__package__ = "expected.package.name"` instead of having an example the OP can use? In my case, __package__ = "main", but even without your suggestion my example ran without error. I fail to see how it is benefiting my example based on its context. – NuclearPeon Sep 24 '15 at 18:44