module has no attribute
Asked Answered
J

4

112

I have a directory with a number of .py files in it. each file defines some classes. I also have an empty __init__.py in the directory.

For example:

myproject
    __init__.py
    mymodule
        __init__.py
        api.py
        models.py
        views.py

I am trying to import mymodule and access the classes defined in all these files:

from myproject import mymodule

print mymodule.api.MyClass 

It gives me an error saying that mymodule has no attribute api. Why? And why I can access just one of the files (models.py) and not the others?

In [2]: dir(banners)
Out[2]:
['__builtins__',
 '__doc__',
 '__file__',
 '__name__',
 '__package__',
 '__path__',
 'models']
Jollenta answered 17/1, 2012 at 17:44 Comment(1)
Wow, Python's amazingly intuitive import system at it again. Definitely never causes people problems.Familial
I
119

The problem is submodules are not automatically imported. You have to explicitly import the api module:

import myproject.mymodule.api
print myproject.mymodule.api.MyClass

If you really insist on api being available when importing myproject.mymodule you can put this in myproject/mymodule/__init__.py:

import myproject.mymodule.api

Then this will work as expected:

from myproject import mymodule

print mymodule.api.MyClass 
Inflammatory answered 17/1, 2012 at 17:56 Comment(4)
Isn't this a bit cumbersome? Is there a way to switch on importing of sub-modules (with the full qualifying names, e.g foo.bar.baz) by default?Iodize
I'm fine doing the full import, but in the rest of the code I'd like to drop myproject and refer to mymodule.api which does not seem to be possible?Zachariah
@AmirRosenfeld No, there is no such way, and there cannot possibly be such a way, because the file system does not actually dictate where the sub-modules are or what all their names are. Python allows for huge amounts of customization of the import system. Aside from that, it would be a terrible default behaviour, because in most cases it would slow down all the top-level imports in order to import huge amounts of code that isn't actually used later.Effects
@Zachariah Using relative imports within the package will save you a lot of typing. More complex renamings are possible, but they require a proper understanding of the import system which is probably beyond the scope of even a separate Stack Overflow Q&A, let alone the comments section.Effects
F
43

Also check whether you didn't name your python file the same as the module you are trying to import.

Freeborn answered 29/3, 2020 at 11:3 Comment(4)
Yes, this is a strange piece of Python rubric, that the filename must be different from the module name. Be warned!Pelvis
Oh wow, that's a difficult one to google!Alienate
The file name does not need to differ from the module name. In fact, the file name for the module that you are implementing, by definition, dictates the module name. This is a completely unrelated problem that comes up when you want to import a different module from the current file, but the current file has the same name as the other module you want to import. The problem is that every Python source code file defines a module, whether or not you intend for it to be imported. The modules defined by source code files can, therefore, attempt to import themselves.Effects
The canonical for this problem is Importing a library from (or near) a script with the same name raises "AttributeError: module has no attribute" or an ImportError or NameError.Effects
D
2

Modules don't work like that.

from myproject.mymodule import api
print api.MyClass
Digression answered 17/1, 2012 at 17:45 Comment(4)
I know I can do that. Is it possible to do using the dotted names?Jollenta
@akonsu, simply do import myproject.mymodule.api then and access it through myproject.mymodule.api.MyClass.Inflammatory
well, i think this is a question about the language in general, not about how I can get my code to work. I am curious as to whether this can be achieved. can I make it access my classes through 'mymodule.api...' without the leading 'myproject'?Jollenta
you could do import myproject.mymodule as mymodule but it seems confusing to meRhinal
E
-5

You need an __init__.py in the myproject directory too. So your module structure should be:

myproject
    __init__.py
    mymodule
        __init__.py
        api.py
        models.py
        views.py
Eakin answered 17/1, 2012 at 17:49 Comment(2)
That's exactly the module structure in the question...Fax
Aside from that, since Python 3.3 empty __init__.py files are not required to set up directories as packages (although they do influence the lookup order for absolute imports). A missing __init__.py is not the reason for a relative import failing in modern Python.Effects

© 2022 - 2024 — McMap. All rights reserved.