pythonimporterrorcircular-dependency

I have this program which im trying to work with a json and see what talents are available, but when I try to run talents i get a error when importing


Main.py

from pygame import *
import pygame
from Talent_List import *
import requests
import json
import sys
import time


class DeepwokenBuilder:
    def __init__(self):
        self.active = True

    def start(self):
        while self.active:
            print(" Starting... welcome to the deepwoken talent checker! \n")
            self.questions()

            q = input("Would you like to continue? ")

            if q == "yes " or q == "y":
                continue

            else:
                print(" Goodbye, ending loop")
                self.active = False
                break

    def talent_reqs(self):
        pass


    def questions(self):
        flame = input("How much flamecharm do you have?\n")
        gale = input("How much galebreath do you have?\n")
        frost = input("How much frostdraw do you have?\n")
        thunder = input('How much thunder do you have?\n')

        attributes = [flame, gale, frost, thunder]

        return attributes

        def controller(self):
            pass


if __name__ == '__main__':
    Db = DeepwokenBuilder()
    Db.start()

Talents.py

import json
from Main import DeepwokenBuilder


# make talent logic here ig

with open(r'C:\Users\Zahir\Desktop\DeepwokenBuilder\Deepwoken Builder\Talent_list.json') as f:
    Talent_list = json.load(f)


class Talents:
    def __init__(self):
        self.Talent_list = Talent_list
        self.flamecharm = Talent_list['flamecharm']
        self.galebreath = Talent_list['galebreath']
        self.frostdraw = Talent_list['frostdraw']
        self.thundercall = Talent_list['thundercall']
        self.base = Talent_list['base']


    def display_talents(self):
        db = DeepwokenBuilder()

        attributes = db.questions()
        print(attributes)

        for i, v in self.Talent_list.items():
            attunement = i
            for i, v in v.items():
                talent_name = i
                talent_req = v

                print(f"{talent_name, talent_req}, {attunement} ")
                print(attributes)

                # if attributes < whatever

tt = Talents()
tt.display_talents()

Error:

ImportError: cannot import name 'DeepwokenBuilder' from partially initialized module 'Main' (most likely due to a circular import) (DeepwokenBuilder\Deepwoken Builder\Main.py)

I'm trying to figure out why I'm having the error.


Solution

  • You have problem with import because you have real problem in your logic:

    1. You create two instances of DeepwokenBuilder(), and when you change something in one instance then other will not have it. You should create only one DeepwokenBuilder() and send it as parameter to other class - as Talents(db) or tt.display_talents(db)
    2. You have to create Talents() in Main.py after you create DeepwokenBuilder
        db = DeepwokenBuilder()
        tt = Talents()
        tt.display_talents(db)
        db.start()
    

    If you change it then you don't have to import DeepwokenBuilder in Talents.py and this resolves problem with partially initialized module


    Full working example.

    (PEP8: lower_case_name.py for files)

    (PEP 8 -- Style Guide for Python Code)

    talents.py

    import json
    import os
    
    class Talents:
    
        def __init__(self):
    
            #self.path = r'C:\Users\Zahir\Desktop\DeepwokenBuilder\Deepwoken Builder\Talent_list.json'
            self.base_dir = os.path.abspath(os.path.dirname(__file__))        
            self.path = os.path.join(self.base_dir, 'Talent_list.json')
            
            #print('[DEBUG] Talents: self.path:', self.path)
            
            with open(self.path) as f:
                self.data = json.load(f)
                
            self.flamecharm = self.data['flamecharm']
            self.galebreath = self.data['galebreath']
            self.frostdraw = self.data['frostdraw']
            self.thundercall = self.data['thundercall']
            self.base = self.data['base']
    
        def display_talents(self, db):
    
            attributes = db.questions()
            print(attributes)
    
            for attunement, value in self.data.items():
                for talent_name, talent_req in value.items():
                    print(f"{talent_name, talent_req}, {attunement} ")
                    print(attributes)
    
                    # if attributes < whatever
    

    main.py

    #import pygame   # PEP8: `import *` is not preferred
    from talents import Talents  # PEP8: `lower_case_names` for files with code - `talents.py` 
    
    class DeepwokenBuilder:
        def __init__(self):
            self.active = True
    
        def start(self):
            while self.active:
                print(" Starting... welcome to the deepwoken talent checker! \n")
                self.questions()
    
                q = input("Would you like to continue? ")
                q = q.strip().lower()
                
                #if q !== "yes" and q != "y":
                if q not in ("yes", "y"):
                    print(" Goodbye, ending loop")
                    self.active = False
                    break
    
        def questions(self):
            flame = input("How much flamecharm do you have?\n")
            gale = input("How much galebreath do you have?\n")
            frost = input("How much frostdraw do you have?\n")
            thunder = input('How much thunder do you have?\n')
    
            self.attributes = [flame, gale, frost, thunder]
    
            return self.attributes
    
    
    if __name__ == '__main__':
        db = DeepwokenBuilder()   # PEP8: `lower_case_names` for variables
        tt = Talents()
        tt.display_talents(db)
        db.start()
    

    example Talent_list.json if someone would like to test it

    {
    "flamecharm": {"A": 1, "B": 2, "C": 3},
    "galebreath": {"A": 1, "B": 2, "C": 3},
    "frostdraw": {"A": 1, "B": 2, "C": 3},
    "thundercall": {"A": 1, "B": 2, "C": 3},
    "base": {"A": 1, "B": 2, "C": 3}
    }