yet another thread, but I don’t really get it…
I have an application (telegram python bot) with a lot of CONSTANTS in it, so I did a bit of a structure here:
bot/
api.py
bot.py
constants.py
functions.py
keyboards.py
Main execution file is: bot.py
Below is the imports from those files:
# bot.py
import os, logging, re
import constants as c
from telegram import Update
from telegram.ext import filters, ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, ConversationHandler, CallbackQueryHandler
from keyboards import START_KEYBOARD, INFO_KEYBOARD, SETTINGS_KEYBOARD, PUNCH_KEYBOARD
import api as a
import functions as f
# api.py
import requests, openai
import constants as c
import functions as f
# constants.py
import os
import datetime as d
import functions as f
# functions.py
import api as a
import constants as c
from typing import Literal
from datetime import datetime
from telegram import Update
# keyboards.py
from telegram import ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton
import constants as c
bot_1 | Traceback (most recent call last):
bot_1 | File "/opt/app/bot.py", line 2, in <module>
bot_1 | import constants as c
bot_1 | File "/opt/app/constants.py", line 3, in <module>
bot_1 | import functions as f
bot_1 | File "/opt/app/functions.py", line 1, in <module>
bot_1 | import api as a
bot_1 | File "/opt/app/api.py", line 58, in <module>
bot_1 | def req_tes_headers(host=c.TES_OAUTH_HOST ,token=''):
bot_1 | ^^^^^^^^^^^^^^^^
bot_1 | AttributeError: partially initialized module 'constants' has no attribute 'TES_OAUTH_HOST' (most likely due to a circular import)
So my question is why the **** I still getting this error?
2
Answers
Your
constants
module has no reason to import any other module AFAICT. By importingfunctions
(which itself depends on constants defined inconstants
to define defaults for some of the functions it provides), you end up creating a circular import which requires elements from both modules during the definition of things in those modules, which causes your problem.If the
constants
module is made into a leaf module in the package (imported by other modules, but not itself importing anything from other modules in the package), your problem should disappear; the first thing to importconstants
will import it completely before it tries to use anything from it (e.g.functions
using it to set defaults for one of the functions it defines). You’ll still have some circular imports involved (e.g.api
importingfunctions
and vice-versa), but so long as none of them require anything from the module they import at import time, you should be okay.This is due to circular import.
Here’s how it happens:
Constants.py is not fully initialized yet because it’s waiting for functions.py to be initialized, which in turn is waiting for api.py to be initialized. This is the circular import.
To fix this, you need to refactor your code to remove the circular dependency. One way to do this is to move the import statements inside the functions that use them.