I’m have a script ‘zigbot.py’ which was working, but I’m restructuring to dockerize and now I’m questioning my ability to code at all. What I’m trying to do is have a telegram-bot container, and a ‘web’ container (FLASK), and a nginx container.
Next to zigbot.py I have a folder – ‘bot’, which has many of my scripts and functions in. Upon trying from bot.somescript import a_function
I am getting error after error.
Project structure
zigbot
bot
bot
__init__.py
conversations.py
ct.py
Docerfile
funcs.py
pricedata.py
requirements.txt
util.py
zigbot.py
nginx
somestuff
web
app
migrations
templates
__init__.py
config.py
forms.py
functions.py
models.py
routes.py
signals.py
__init__.py
Dockerfile
requirements.txt
zigweb.py
When running the code below, I get a whole range of strange errors – the one listed below shows ImportError – it can’t find ‘onboard’ in funcs, but its definitely there. Before the restructure, this was working. If I comment out ‘onboard’ it errors on every function in the list.
from bot.conversations import key_conversation
from bot.crypto_functions import satoshi_to_btc
from bot.funcs import onboard, main_menu, new_message1, new_keyboard, onboarded_keyboard,
onboarded_message, blank_signal_message, send_signal_format, get_or_create_user, signal_detected_keyboard, log_me
Traceback (most recent call last):
File "zigbot.py", line 15, in <module>
from bot.funcs import onboard, main_menu, new_message1, new_keyboard, onboarded_keyboard,
File "ZigBotbotbotfuncs.py", line 2, in <module>
from zigbot.web.app import db, app
File "ZigBotbotzigbot.py", line 15, in <module>
from bot.funcs import onboard, main_menu, new_message1, new_keyboard, onboarded_keyboard,
ImportError: cannot import name 'onboard'
So I tried adding a .bot.conversation for (relative?) import, but this produces an even weirder error. I’ve included the code, the error, then the function I’m trying to import below:
from .bot.conversations import key_conversation
from .bot.crypto_functions import satoshi_to_btc
from .bot.funcs import onboard, main_menu, new_message1, new_keyboard, onboarded_keyboard,
onboarded_message, blank_signal_message, send_signal_format, get_or_create_user, signal_detected_keyboard, log_me
from ..web.app import db
from ..web.app.models import User, Signal
Traceback (most recent call last):
File "zigbot.py", line 13, in <module>
from .bot.conversations import key_conversation
ModuleNotFoundError: No module named '__main__.bot'; '__main__' is not a package
conversations.py
# Initialise conversationHandler states
def key_conversation(cancel):
# Define keyboards
keyboard = [
[InlineKeyboardButton('Previous', callback_data='onboard:key'),
InlineKeyboardButton('Next', callback_data='onboard:alldone')]]
conversation_keyboard = InlineKeyboardMarkup(keyboard)
Finally, I think I’m getting closer to the problem, I go back to the way I think it’s supposed to be imported. From bot.funcs import x,y,y… I look in funcs.py and this is how its importing some other code from my Flask web app, but it doesn’t like it.
funcs.py
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from web.app import db, app
from web.app.models import User
Traceback (most recent call last):
File "zigbot.py", line 15, in <module>
from bot.funcs import onboard, main_menu, new_message1, new_keyboard, onboarded_keyboard,
File "ZigBotbotbotfuncs.py", line 2, in <module>
from web.app import db, app
ModuleNotFoundError: No module named 'web'
So I change the import to go up a level since web is two levels above bot
– which contains the script I’m importing to. So zigbot>bot>bot>funcs.py
trying to import from zigbot>web>app>
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from ..web.app import db, app
from ..web.app.models import User
import telegram
Traceback (most recent call last):
File "zigbot.py", line 15, in <module>
from bot.funcs import onboard, main_menu, new_message1, new_keyboard, onboarded_keyboard,
File "ZigBotbotbotfuncs.py", line 2, in <module>
from ..web.app import db, app
ValueError: attempted relative import beyond top-level package
This obviously doesn’t work either. Given my structure of having bot
and web
how do I get this to work? I even tried pulling the scripts out of the second ‘bot’ folder but I get the same issues. Finally, my weirdest error which might provide a clue to what I’m doing wrong, if I change the import on funcs.py to go one level up, rather than two, I get an even stranger traceback.
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from .web.app import db, app
from .web.app.models import User
import telegram
Traceback (most recent call last):
File "zigbot.py", line 15, in <module>
from bot.funcs import onboard, main_menu, new_message1, new_keyboard, onboarded_keyboard,
File "C:UsersphillPycharmProjectsZigBotbotbotfuncs.py", line 2, in <module>
from .web.app import db, app
ModuleNotFoundError: No module named 'bot.web'
For clarity I removed some ‘C:Usersphill’ from the tracebacks before realising it was pointless to remove that.
2
Answers
I think there’s a fundamental flaw in your split if you have library dependencies across the boundary. Assuming that there are no imports of bot-modules in your web container, I would suggest breaking off the shared code into a module named
weblib
or something (alongside thebot
-,nginx
– andweb
-folders).You still should not try to import across would-be container boundaries however, so just make sure
weblib
is in your path or installed in your virtual environment or however you want to handle it. Basically,bot
andweb
should run in separate environments and should haveweblib
as a dependency.Someone wiser than me might be able to explain it better.
For relative imports to work all the packages and subpackages must be in the sys.path – to achieve this you should run from the top-level directory as in:
This will make your current working dir (zigbot) available to sys.path and the subpackages will be resolved correctly