Why does importing modules result in a circular import error
I have this for the layout of my project:
projectFolder / setup/ __init__.py setup.py Utils / __init__.py cloudmanager.py startup.py
I am trying to import the Setup
Module inside my cloudmanager.py
script (which is nested in one more directory). I can easily import both the setup
module and the Utils
module inside my startup.py
script since it’s in the root directory.
I’ve tried (inside my cloudmanager.py
script):
from . import setup
Which gives me the error of:
ImportError: cannot import name 'setup' from partially initialized module 'Utils' (most likely due to a circular import)
and I’ve tried:
from .. import setup
Which gives me the error of:
ValueError: attempted relative import beyond top-level package
Any help? There are questions like this out there but they steer towards to using OS, which I’d like to avoid…
Okay, so the reason you’re getting an error importing .. setup
is indeed that you can’t do relative imports when the parent directory is a package. A package is any directory with a __init__.py
file in it.
You could solve this by doing one of two things:
- You could make sure the root of your project is in the Python path and import everything in the root.
- You could make your project’s root directory itself a package and then use relative imports.
Option 1: Importing from the project root
If your projectFolder
folder lives at /home/you/projects/projectFolder
, make sure your PYTHONPATH
has /home/you/projects/projectFolder
in it. For example, when you run your main script, you could set it before hand. In bash (assuming a Unix environment):
export PYTHONPATH=/home/you/projects/projectFolder python /home/you/projects/projectFolder/startup.py
You could also do that inside startup.py, if you want to avoid changing the external environment:
# startup.py import os, sys sys.path.append(os.path.join(os.path.dirname(__file__)))
If you do that in startup.py, the directory of startup.py will always be in the Python path.
Once you one of those, you can base all your imports on the relative location of your project. Eg:
import setup.setup import Utils.cloudmanager
(That will work in every file you import after the sys.path
mutation runs)
Option 2: Relative imports
If you make your project’s root a Python package, you can use relative imports entirely. Eg, you’d have these files:
projectFolder/__init__.py projectFOlder/setup/__init__.py projectFolder/setup/setup.py projectFolder/Utils/__init__.py projectFolder/Utils/cloudmanager.py
If you do that, inside cloudmanager.py
, you could run from .. import setup
just fine.
What do you do?
Both of these are valid options. In general relative imports have less ambiguity, since they avoid name collisions, but they’re a newer feature of Python so option #1 is more common, in general.