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:
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?
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.
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.
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.