Skip to main content

How to Resolve Python Error "AttributeError: partially initialized module ... has no attribute ..." (circular import issue)

The AttributeError: partially initialized module 'X' has no attribute 'Y' (most likely due to a circular import) is a specific type of AttributeError in Python. It signals a problem during the module import process itself, typically caused by a circular dependency where modules end up trying to import each other before they have fully finished loading. Another common trigger is naming a local file the same as a standard or third-party module.

This guide explains circular imports and filename shadowing, demonstrating how they lead to this error and providing effective solutions.

Understanding the Error: Partial Initialization and Circular Imports

When Python imports a module (import my_module), it executes the code in my_module.py from top to bottom to create the module object and populate its namespace with functions, classes, and variables.

A circular import occurs when Module A imports Module B, and Module B also imports Module A (either directly or indirectly through other modules). This creates a dependency loop:

  1. Execution starts in Module A.
  2. Python encounters import B. It pauses A's execution and starts loading Module B.
  3. While executing Module B, Python encounters import A.
  4. Since Module A is already being loaded but hasn't finished, Python doesn't restart loading A. Instead, it adds a partially initialized reference to Module A into Module B's namespace.
  5. If Module B then tries to access an attribute (function, class, variable) from Module A that hasn't been defined yet (because A's execution was paused), the AttributeError: partially initialized module 'A' has no attribute '...' occurs.
  6. A similar error can happen in Module A if it tries to access something from Module B before B has finished its own initialization.

The "partially initialized" state is key – the module object exists, but it's incomplete.

Cause 1: Circular Imports Between Project Files

This is the classic circular dependency between two or more of your own project files.

Error Scenario (A imports B, B imports A)

file_a.py
# === file_a.py ===
import file_b # Tries to import file_b

def function_a():
print("Function A called")
# Tries to use something from file_b *during* file_a's import/initialization
file_b.function_b_utility() # Might cause error if file_b hasn't defined this yet

def utility_a():
print("Utility A")

print("Executing file_a top level")
# If file_b tries to call utility_a before this point, it fails

# Example call that might trigger error in file_b if run directly
# function_a()
file_b.py
# === file_b.py ===
import file_a # Tries to import file_a

def function_b():
print("Function B called")
file_a.utility_a() # Might cause error if file_a hasn't defined this yet

def function_b_utility():
print("Utility B")

print("Executing file_b top level")

# Try using something from file_a immediately
# If file_a is still loading file_b when this line is hit, it will fail
# ⛔️ AttributeError: partially initialized module 'file_a' has no attribute 'utility_a'
function_b()

If you run python file_b.py, it imports file_a. file_a starts, imports file_b. file_b resumes, tries to call function_b. Inside function_b, it needs file_a.utility_a. But file_a is only partially initialized (paused at its import file_b line). If utility_a hasn't been defined yet in file_a, the error occurs in file_b.

Solution 1: Refactor Imports (Import within Function/Method)

Delay the import until it's actually needed inside a function or method. This often breaks the cycle during the initial top-level execution.

file_b_fixed.py
# === file_b_fixed.py ===

# No top-level import of file_a

def function_b():
print("Function B called")
# ✅ Import file_a ONLY when function_b is called
import file_a
file_a.utility_a() # By this time, file_a should have fully initialized

def function_b_utility():
print("Utility B")

print("Executing file_b_fixed top level")
function_b()
note

Caveat: While this fixes the immediate AttributeError, frequent circular imports often indicate a design problem. Relying heavily on function-level imports can make dependencies less clear.

The best solution is usually to refactor your code to eliminate the circular dependency. Often, this involves identifying shared functionality or coordination logic and moving it to a third module, or rethinking class responsibilities.

file_a_refactored.py
# === file_a_refactored.py ===
# (Might import common_utils if needed, but NOT file_b)
# import common_utils

def function_a():
print("Function A called")
# Calls something from common_utils or performs its own logic

def utility_a():
print("Utility A")

print("Executing file_a_refactored")
file_b_refactored.py
# === file_b_refactored.py ===
# (Might import common_utils if needed, but NOT file_a)
# import common_utils

def function_b():
print("Function B called")
# Calls something from common_utils or performs its own logic

def function_b_utility():
print("Utility B")

print("Executing file_b_refactored")
main_app.py
# === main_app.py (Mediator) ===
import file_a_refactored
import file_b_refactored
# Maybe import common_utils

print("Starting main application")
file_a_refactored.function_a()
file_b_refactored.function_b()
file_a_refactored.utility_a()
file_b_refactored.function_b_utility()
print("Main application finished")

Now, main_app.py coordinates the interaction between file_a and file_b, breaking the direct circular import between them.

Cause 2: Filename Shadowing (Specific Circular Import)

This occurs when you name your local script file the same as a standard library module or a third-party package you intend to import (e.g., requests.py, datetime.py, csv.py).

Error Scenario (e.g., requests.py importing requests)

requests.py
# --- Code inside a file named requests.py ---
import requests # This imports THIS file recursively!

def make_request():
try:
# ⛔️ AttributeError: partially initialized module 'requests'
# has no attribute 'get' (most likely due to a circular import)
# The real 'requests' module was never fully imported because
# this file shadowed it. The 'requests' being accessed here
# is this partially loaded file itself.
response = requests.get("https://example.com")
print(response.status_code)
except AttributeError as e:
print(e)

make_request()

When import requests runs, Python finds the local requests.py first. This starts a recursive import loop. When requests.get is called, the module object requests refers to the partially initialized local file, which doesn't yet (and never will) have the get method defined.

Solution: Rename Your Conflicting File

Avoid using names of built-in modules or installed packages for your own files. Rename your requests.py (or datetime.py, etc.) to something unique like my_requests_handler.py, date_script.py, or main.py.

Debugging the Error

Analyze the Traceback

The error message and traceback are crucial. They will show:

  • The specific attribute that couldn't be found (...has no attribute 'Y').
  • The module that was partially initialized (partially initialized module 'X').
  • Often, the sequence of imports leading to the circular dependency. Look at the file paths mentioned in the traceback.

Check module.__file__

If you suspect filename shadowing, explicitly check which file was loaded:

import requests # Or the module name causing the issue

print(requests.__file__)

If this points to your local script instead of the standard library/site-packages location, renaming your file is necessary.

Inspect dir(module)

Right after the problematic import, print dir(module_object). If the module is partially initialized due to shadowing or a circular import, the output will be very minimal, likely missing the expected functions/classes/variables. A correctly imported module will show a much longer list.

Check for Standard Library Conflicts (sys.builtin_module_names)

To see if your chosen filename conflicts with a built-in module:

import sys
print(sys.builtin_module_names)

Avoid using any of these names for your files. Also, check your installed packages (pip list) for potential conflicts.

Conclusion

The AttributeError: partially initialized module... signals an issue during the import process itself, usually:

  1. Circular Imports: Module A imports B, and B imports A, leading to one trying to access attributes of the other before it's fully loaded. Solution: Refactor the code structure (recommended) or delay imports by placing them inside functions (use cautiously).
  2. Filename Shadowing: Your local file has the same name as a module you're importing (e.g., requests.py), causing a specific type of circular import. Solution: Rename your local file.

Carefully analyzing the traceback and potentially using module.__file__ or dir(module) helps pinpoint the cause, allowing you to apply the appropriate fix by restructuring imports or renaming files.