pythonenvironment-variablesaiogramenviron

A variable imported with environ doesn't transfer to another file


I have two files in my Telegram bot called loader.py and start_message.py:

loader.py:

from aiogram import Bot, Dispatcher
import environ
from environment import TOKEN


bot = Bot(token=TOKEN)
dp = Dispatcher(bot)

loader.py works perfectly well and the environment variable imports there without raising errors. However, when I try to pass a variable "bot" to the "start_message.py" file:

from aiogram import types
from loader import bot, dp


@dp.message_handler(commands=["start"])
async def send_start_message(message: types.Message):
    await bot.send_message(message.chat.id, "Hello!")

I receive the following:

 File ~/***/venv/lib/python3.10/site-packages/environ/environ.py:279 in get_value
    raise ImproperlyConfigured(error_msg)

ImproperlyConfigured: Set the TOKEN environment variable

It means that the value for TOKEN is not set, although it was set in another file. I tried adding the following lines to the code in start_message.py to initialize the TOKEN variable required for "bot" again:

import environ
env = environ.Env(DEBUG=(bool, False))
environ.Env.read_env(env_file="data/.env")

But the same error kept appearing for some reason. Only when I define bot in start_message.py it works, but it's not what I want to do for every handler file.

The file that is meant to execute the script is main.py. It raises no errors, but the bot isn't responding to the command /start. When debugging, I identified a problem in start_message.py.

main.py:

from aiogram import executor
import nest_asyncio

nest_asyncio.apply()

if __name__ == "__main__":
    from handlers import dp
    executor.start_polling(dp)

notify_admins.py:

from loader import bot, dp
from aiogram import types
from datetime import datetime
from environment import admin_chat

admin_chat = int(admin_chat)

@dp.message_handler(commands=["start"])
async def send_startup_message_to_admins(message: types.Message):
    await bot.send_message(admin_chat, f"[{datetime.now()}] Bot was started by" \
                           f"@{message.from_user.username}, " \
                           f"ID: {message.from_user.id}")

environment.py:

import environ
import pathlib

env = environ.Env(DEBUG=(bool, False))

current_dir = pathlib.Path(__file__).resolve().parent
env_file = pathlib.Path(current_dir, "./data/.env")
with open(env_file, 'r') as fd:
    environ.Env.read_env(env_file=fd)

TOKEN = env("TOKEN")
admin_chat = env("admin_chat")

The file hierarchy is the following:

my_project
├──__pycache__
├── .spyproject
├──core
│  ├──__init__.py
│  ├──functions
│  │  └──__init__.py
│  │  └──notify_admins.py
│  └──handlers
│     └──__init__.py
│     └──start_message.py
├──data
│  └──.env
├──venv
├──environment.py
├──loader.py
└──main.py

Full error traceback:

runfile('/home/user/***/handlers/start_message.py', wdir='/home/user/***/handlers', current_namespace=True)
Traceback (most recent call last):

  File ~/***/venv/lib/python3.10/site-packages/environ/environ.py:275 in get_value
    value = self.ENVIRON[var]

  File /usr/lib/python3.10/os.py:679 in __getitem__
    raise KeyError(key) from None

KeyError: 'TOKEN'


During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File ~/***/venv/lib/python3.10/site-packages/spyder_kernels/py3compat.py:356 in compat_exec
    exec(code, globals, locals)

  File ~/***/handlers/start_message.py:9
    from loader import bot, dp

  File ~/***/loader.py:14
    bot = Bot(token=env("TOKEN"))

  File ~/***/venv/lib/python3.10/site-packages/environ/environ.py:125 in __call__
    return self.get_value(var, cast=cast, default=default, parse_default=parse_default)

  File ~/***/venv/lib/python3.10/site-packages/environ/environ.py:279 in get_value
    raise ImproperlyConfigured(error_msg)

ImproperlyConfigured: Set the TOKEN environment variable

Solution

  • I'm not sure what the problem is, but you can try the following code

    env = environ.Env(DEBUG=(bool, False))
    current_dir = pathlib.Path(__file__).resolve().parent
    env_file = pathlib.Path(current_dir, "./data/.env")
    with open(env_file, 'r') as fd:
        environ.Env.read_env(env_file=fd)