Importing packages in Python

I am probably missing something obvious but anyway:

When you import a package like os in python, you can use any submodules/subpackages off the bat. For example this works:

>>> import os
>>> os.path.abspath(...)

However I have my own package which is structured as follows:

FooPackage/
  __init__.py
  foo.py

and here the same logic does not work:

>>> import FooPackage
>>> FooPackage.foo
AttributeError: 'module' object has no attribute 'foo'

What am I doing wrong?


When you import FooPackage, Python searches the directories on PYTHONPATH until it finds a file called FooPackage.py or a directory called FooPackage containing a file called __init__.py. However, having found the package directory, it does not then scan that directory and automatically import all .py files.

There are two reasons for this behaviour. The first is that importing a module executes Python code which may take time, memory, or have side effects. So you might want to import a.b.c.d without necessarily importing all of a huge package a. It's up to the package designer to decide whether a's __init__.py explicitly imports its modules and subpackages so that they are always available, or whether or leaves the client program the ability to pick and choose what is loaded.

The second is a bit more subtle, and also a showstopper. Without an explicit import statement (either in FooPackage/__init__.py or in the client program), Python doesn't necessarily know what name it should import foo.py as. On a case insensitive file system (such as used in Windows), this could represent a module named foo, Foo, FOO, fOo, foO, FoO, FOo, or fOO. All of these are valid, distinct Python identifiers, so Python just doesn't have enough information from the file alone to know what you mean. Therefore, in order to behave consistently on all systems, it requires an explicit import statement somewhere to clarify the name, even on file systems where full case information is available.


You need to import the submodule:

import FooPackage.foo

What you're doing is looking for foo in FooPackage/__init__.py. You could solve it by putting import FooPackage.foo as foo (or from . import foo) in FooPackage/__init__.py, then Python will be able to find foo there. But I recommend using my first suggestion.


You need to add from . import foo to the __init__.py file in your package.


There are some important misconceptions that need to be addressed, specifically with terminology. First, usually, when you think that you are importing a package in python, what you are actually importing is a module. You should use the term package when you are thinking in terms of file system substructure that helps you organize your code. But from the code perspective, whenever you import a package, Python treats it as a module. All packages are modules. Not all modules are packages. A module with the __path__ attribute is considered a package.

You can check that os is a module. To confirm this you can do:

import os
print(type(os)) # will print: <type 'module'>

In your example, when you do import FooPackage, FooPackage is treated and considered to be a module too, and its attributes (functions, classes, etc.) are supposedly defined in __init__.py. Since your __init__.py is empty, it cannot find foo.

Outside of import statements you cannot use '.' notation to address modules inside of modules. The only exception happens if a module is imported in the intended parent's package __init__.py file. To make it clear, let's do some examples here:

Consider your original structure:

FooPackage/
  __init__.py
  foo.py

Case 1: __init__.py is an empty file

#FooPackage imported as a module
import FooPackage 

#foo is not a name defined in `__init__.py`. Error
FooPackage.foo 

#FooPackage.foo imported as a module
import FooPackage.foo

#Error, foo has not been imported. To be able to use foo like this,
#you need to do: import FooPackage.foo as foo
foo.anything

#Not error, if anything is defined inside foo.py
FooPackage.foo.anything

Case 2: __init__.py has line import foo in it:

import FooPackage

#Now this is good. `foo` is sort of considered to be an attribute of 
#FooPackage
FooPackage.foo

Now, suppose that foo is no longer a module, but a function that you define in __init__.py. if you do import FooPackage.foo, it will throw an error saying that foo is not a module.