renatodamas
renatodamas

Reputation: 19565

Python, importing from same module: ImportError: cannot import name 'blah', __name__ == '__main__'

Very easy issue to replicate. My current setup is:

package/
    __init__.py
    run.py

In my __init.py__ I have:

blah = 4

And in my run.py I have:

from package import blah


if __name__ == '__main__':
    print(blah)

I simply run it with python run.py. But I am getting ImportError: cannot import name 'blah'.

How come I am not being able to import a variable from my package? I know how to workaround it, I am rather interested in knowing the reason for the error.

Upvotes: 4

Views: 5420

Answers (4)

d_kennetz
d_kennetz

Reputation: 5359

You are clearly trying to execute this as a package, but you are running "run.py" as if it were a standard python script. run.py does not have a concept of module in the sense of how you are trying to run it. You need to re-architect your design here. in the package module run.py would be a module (these are your naming conventions here). So module is the package, and run.py is a module. You then need a __main__.py to execute this as a package and you need to change your run.py:

run.py:

#!/usr/bin/env python3

from module1 import blah

def run():
    print(blah)

__main__.py:

#!/usr/bin/env python3
from module1 import run

def main():
    run.run() # run is the module name, and run is also the function name so we execute with run.run

main()

__init__.py:

blah = 4

directory structure:

module1/ - __init__.py - __main__.py - run.py

to execute (outside of module1):

[dkennetz@nodem103  fun]$ python3.5 -m module1
4

If you do not want to make this a package, you should simply create a directory called package and inside you can make run.py and variables.py.

variables.py:

blah=4
blahblah=8
blahblahblah=12

run.py:

from variables import blah
print(blah)

prints 4

if you changed run.py to:

from variables import blah, blahblah

print(blah)
print(blahblah)

[dkennetz@nodem103  package]$ python3.5 run.py
4
8

Or you can import all variables by changing run.py to:

from variables import *
print(blah)
print(blahblah)
print(blahblahblah) # if this was added to variables.py as 12

It returns:

[dkennetz@nodem103  package]$ python3.5 run.py
4
8
12

Upvotes: 4

LiuXiMin
LiuXiMin

Reputation: 1265

In python, package and module are two different concept. module is single py file and package must be a dir which must contain __init__.py.

__init__.py is for packages, when you run run.py in package dir, package dir can not be treated as a package, and package dir of course are not module. So it raised the error: ModuleNotFoundError: No module named xxxx.

When a regular package is imported, this__init__.py file is implicitly executed, and the objects it defines are bound to names in the package’s namespace.

5. The import system — Python 3.7.4rc1 documentation

Upvotes: 0

john-hen
john-hen

Reputation: 4866

I'm assuming you are running python run.py from within the directory package. Python then looks for a package (a directory) or a module (.py file) named "package" inside that directory, but neither exists. As it cannot import the symbol blah, it raises an ImportError.

Upvotes: 2

Zubda
Zubda

Reputation: 963

Your issue is that you are trying to import from the module you are in.

Here is my structure

[syspath]
$ tree
.
├── mod
│   ├── __init__.py
│   └── run.py
└── orun.py

1 directory, 3 files

[syspath]
$ cat mod/run.py 
#from mod import blah
from . import blah

print(blah)

[syspath]
$ cat orun.py 
from mod import blah

print(blah)

[syspath]
$ python3 orun.py 
4

[syspath]
$ python3 -m mod.run
4

Being within the module directory you are effectively a part of the module and can't import it, you can however reference it as a sibling but only if you are being run as a part of the module, as in python3 -m mod.run the -m is run this as a module.

A bit more of an understanding, python import looks for entries available in sys.path,
Here are the sys.paths found in the orun.py (outside of the module), and mod/run.py within the module.

[syspath]
$ python3 orun.py 
['~/syspath',
 '/usr/lib/python37.zip',
 '/usr/lib/python3.7',
 '/usr/lib/python3.7/lib-dynload',
 '~/.local/lib/python3.7/site-packages',
 '/usr/local/lib/python3.7/dist-packages',
 '/usr/lib/python3/dist-packages']

[syspath]
$ python3 mod/run.py 
['~/syspath/mod',
 '/usr/lib/python37.zip',
 '/usr/lib/python3.7',
 '/usr/lib/python3.7/lib-dynload',
 '~/.local/lib/python3.7/site-packages',
 '/usr/local/lib/python3.7/dist-packages',
 '/usr/lib/python3/dist-packages']

As you see when you are inside of mod you can't find another mod inside of it.

Try adding a new file in the directory with the same name module.py and put a different value for blah and you will see the code execute with that value.

[syspath]
$ tree
.
├── mod
│   ├── __init__.py
│   ├── mod.py
│   └── run.py
└── orun.py

1 directory, 4 files

[syspath]
$ cat mod/mod.py 
blah = 40

[syspath]
$ python3 mod/run.py 
40

Upvotes: 1

Related Questions