0

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
CallMeStag
  • 5,467
  • 1
  • 7
  • 22
Anna
  • 101
  • 8
  • Can you provide additional information regarding the file hierarchy and the file that executes the Python script? – LtGenFlower Jun 21 '23 at 09:17
  • Show the full traceback of the error as properly formatted text (formatted as code) in the question. – Michael Butscher Jun 21 '23 at 09:24
  • The only `environ` module I can find is an alpha version from 2007. Is that what you are using? – guidot Jun 21 '23 at 09:24
  • file hierarchy added, executing file added – Anna Jun 21 '23 at 09:30
  • I am using python-environ released in 2020 – Anna Jun 21 '23 at 09:30
  • full traceback added – Anna Jun 21 '23 at 09:34
  • Does your `data/.env` file actually *have* a value for `TOKEN` in it? – user2357112 Jun 21 '23 at 09:48
  • Yes, it does. When doing print(env("TOKEN")) in loader.py, it returns the value – Anna Jun 21 '23 at 09:49
  • 1
    I'm not sure what the problem is, but you can try the following code: ```python 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) ``` – LtGenFlower Jun 21 '23 at 10:09
  • Thanks! Now everything imports with no errors. I wonder what the problem was. – Anna Jun 21 '23 at 10:14
  • OK now I have another problem. While using pathlib to read .env in notify_admins.py, I run main.py and get the ChatNotFound error which means that the value has not been imported properly. Redefined it explicitly as int, got ValueError because None cannot be int. Again, there is a value in .env – Anna Jun 21 '23 at 10:52
  • add some notify_admins.py code – LtGenFlower Jun 21 '23 at 10:56
  • I need more than one env variable, so I've initialized an initializer environment.py for them not to copypaste the code you've provided to every file. environment.py is also provided as well as notify_admins.py. Thanks for your help once again – Anna Jun 21 '23 at 11:19
  • your loader.py is still like in question? – LtGenFlower Jun 21 '23 at 11:22
  • let me update it – Anna Jun 21 '23 at 11:22
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/254174/discussion-between-ltgenflower-and-anna). – LtGenFlower Jun 21 '23 at 11:23

1 Answers1

1

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)
  • This solves only one instance of passing an environ value between files among the many that I have now since my code grows. Though it is a solution. Great thanks! Would be grateful for an explanation of why it occurs. – Anna Jun 21 '23 at 10:56