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)
Why am I getting this error?
Your constants
module has no reason to import any other module AFAICT. By importing functions
(which itself depends on constants defined in constants
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 import constants
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
importing functions
and vice-versa), but so long as none of them require anything from the module they import at import time, you should be okay.