54

I have the following directory:

mydirectory
├── __init__.py
├── file1.py 
└── file2.py

I have a function f defined in file1.py.

If, in file2.py, I do

from .file1 import f

I get the following error:

SystemError: Parent module '' not loaded, cannot perform relative import

Why? And how to make it work?

double-beep
  • 5,031
  • 17
  • 33
  • 41
John Smith Optional
  • 22,259
  • 12
  • 43
  • 61
  • Are you running `file2.py` directly? – Blender May 19 '13 at 17:31
  • yes I'm doing: `python3 file2.py` from the command line – John Smith Optional May 19 '13 at 17:32
  • 20
    If a python module is part of a package you *shouldn't* launch it as main. If you distribute your library the packages will go into `site-packages` but scripts should go to `/usr/bin` or something like that(hence the need for absolute imports). There should be a clear distinction between a python module that was written to be executed and one that was written to be part of a library. – Bakuriu May 19 '13 at 19:19
  • 1
    @Bakuriu Your comment should be an answer. – Kevin Oct 17 '15 at 20:03
  • 1
    @kevin Thanks. I've decided to expand it a bit and add it as an answer. – Bakuriu Oct 18 '15 at 06:43

4 Answers4

45

Launching modules inside a package as executables is a bad practice.

When you develop something you either build a library, which is intended to be imported by other programs and thus it doesn't make much sense to allow executing its submodules directly, or you build an executable in which case there's no reason to make it part of a package.

This is why in setup.py you distinguish between packages and scripts. The packages will go under site-packages while the scripts will be installed under /usr/bin (or similar location depending on the OS).

My recommendation is thus to use the following layout:

/
├── mydirectory
|    ├── __init__.py
|    ├── file1.py 
└── file2.py

Where file2.py imports file1.py as any other code that wants to use the library mydirectory, with an absolute import:

from mydirectory.file1 import f

When you write a setup.py script for the project you simply list mydirectory as a package and file2.py as a script and everything will work. No need to fiddle with sys.path.

If you ever, for some reason, really want to actually run a submodule of a package, the proper way to do it is to use the -m switch:

python -m mydirectory.file1

This loads the whole package and then executes the module as a script, allowing the relative import to succeed.

I'd personally avoid doing this. Also because a lot of people don't even know you can do this and will end up getting the same error as you and think that the package is broken.


Regarding the currently accepted answer, which says that you should just use an implicit relative import from file1 import f because it will work since they are in the same directory:

This is wrong!

  • It will not work in python3 where implicit relative imports are disallowed and will surely break if you happen to have installed a file1 module (since it will be imported instead of your module!).
  • Even if it works the file1 will not be seen as part of the mydirectory package. This can matter.

    For example if file1 uses pickle, the name of the package is important for proper loading/unloading of data.

oulenz
  • 1,199
  • 1
  • 15
  • 24
Bakuriu
  • 98,325
  • 22
  • 197
  • 231
  • 1
    Is it also a bad practice if you have a unit test file in the same directory and you want to run that unit test file? – gsanta Jan 24 '17 at 19:01
  • @gsanta Why would you put unittests there? The typical project structure have a `test` or `tests` directory that contains all the test file, while the actual sources are in a different directory. – Bakuriu Jan 24 '17 at 19:16
  • I'm coming from the 'javascript world' where there is a growing trend of putting the unit test file next to the file you want to test, and I find it to be a good practice. But maybe it is not so popular in python programming. (And sometimes I would like to run only that test file not all the unit test files, when I want to quickly verify that it is working) – gsanta Jan 24 '17 at 19:22
  • 1
    @gsanta It seems like Javascript lacks proper test discovery tools. For example in python using Nose it's trivial to automatically discover the tests, and also you can simply invoke it with the name of the test as argument and it will only perform those tests... if you only work from an IDE, they usually provide a built-in tester that does the same. Basically doing that is only slightly more convenient if you do everything by hand. – Bakuriu Jan 24 '17 at 19:29
  • Nah JS has that. I too am coming from the JS world and find this "bad practice" a bit peculiar. – Tucker Connelly Jan 26 '17 at 01:13
24

When launching a python source file, it is forbidden to import another file, that is in the current package, using relative import.

In documentation it is said:

Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.

So, as @mrKelley said, you need to use absolute import in such situation.

Community
  • 1
  • 1
stalk
  • 11,934
  • 4
  • 36
  • 58
  • 1
    Thank you! This simple and clear answer finally made me understand why the relative imports didn't work as I thought when running as a command line! – Xavier Aug 04 '20 at 20:06
23

since file1 and file2 are in the same directory, you don't even need to have an __init__.py file. If you're going to be scaling up, then leave it there.

To import something in a file in the same directory, just do like this

from file1 import f

i.e., you don't need to do the relative path .file1 because they are in the same directory.

If your main function, script, or whatever, that will be running the whole application is in another directory, then you will have to make everything relative to wherever that is being executed.

mrKelley
  • 3,365
  • 2
  • 21
  • 28
0
myproject/

mypackage
├── __init__.py
├── file1.py
├── file2.py 
└── file3.py

mymainscript.py

Example to import from one file to another

#file1.py
from myproject import file2
from myproject.file3 import MyClass

Import the package example to the mainscript

#mymainscript.py
import mypackage

https://docs.python.org/3/tutorial/modules.html#packages

https://docs.python.org/3/reference/import.html#regular-packages

https://docs.python.org/3/reference/simple_stmts.html#the-import-statement

https://docs.python.org/3/glossary.html#term-import-path

The variable sys.path is a list of strings that determines the interpreter’s search path for modules. It is initialized to a default path taken from the environment variable PYTHONPATH, or from a built-in default if PYTHONPATH is not set. You can modify it using standard list operations:

import sys
sys.path.append('/ufs/guido/lib/python')
sys.path.insert(0, '/ufs/guido/myhaxxlib/python')

Inserting it at the beginning has the benefit of guaranteeing that the path is searched before others (even built-in ones) in the case of naming conflicts.

The Demz
  • 7,066
  • 5
  • 39
  • 43