Импорт функции из одноуровневой папки в python вызывает странные ошибки - PullRequest
0 голосов
/ 02 октября 2019

У меня есть скрипт 'zigbot.py', который работал, но я реструктурирую, чтобы докеризировать, и теперь я вообще сомневаюсь в своей способности писать код. То, что я пытаюсь сделать, это иметь контейнер telegram-bot, контейнер 'web' (FLASK) и контейнер nginx.

Рядом с zigbot.py у меня есть папка 'bot', в которой находятся многие мои скрипты и функции. При попытке from bot.somescript import a_function я получаю ошибку после ошибки.

Структура проекта

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

При выполнении приведенного ниже кода я получаю целый ряд странных ошибок - в приведенной ниже таблице показана ошибка ImportError - он не может найти «встроенный» в функциях, но он определенно есть. До реструктуризации это работало. Если я закомментирую «на борту», ​​это приведет к ошибкам для каждой функции в списке.

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 "ZigBot\bot\bot\funcs.py", line 2, in <module>
    from zigbot.web.app import db, app
  File "ZigBot\bot\zigbot.py", line 15, in <module>
    from bot.funcs import onboard, main_menu, new_message1, new_keyboard, onboarded_keyboard, \
ImportError: cannot import name 'onboard'

Поэтому я попытался добавить .bot.conversation для (относительного?) Импорта, но это приводит к еще более странным последствиям. ошибка. Я включил код, ошибку, а затем функцию, которую я пытаюсь импортировать ниже:

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

convations.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)

Наконец, я думаю, что яПриближаясь к проблеме, я возвращаюсь к тому способу, который, как мне кажется, должен быть импортирован. Из bot.funcs import x, y, y ... Я смотрю в funcs.py, и вот как он импортирует какой-то другой код из моего веб-приложения Flask, но ему это не нравится.

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 "ZigBot\bot\bot\funcs.py", line 2, in <module>
    from web.app import db, app
ModuleNotFoundError: No module named 'web'

Поэтому я изменяю импорт, чтобы подняться на уровень, так как web на два уровня выше bot - который содержит скрипт, в который я импортирую. Так что zigbot>bot>bot>funcs.py пытается импортировать из 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 "\ZigBot\bot\bot\funcs.py", line 2, in <module>
    from ..web.app import db, app
ValueError: attempted relative import beyond top-level package

Это, очевидно, тоже не работает. Учитывая мою структуру наличия bot и web, как мне заставить это работать? Я даже пытался вытащить скрипты из второй папки «бот», но у меня возникли те же проблемы. Наконец, моя самая странная ошибка, которая может дать понять, что я делаю неправильно, если я изменю импорт файла funcs.py, чтобы перейти на один уровень вверх, а не на два, я получу еще более странную трассировку.

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:\Users\phill\PycharmProjects\ZigBot\bot\bot\funcs.py", line 2, in <module>
    from .web.app import db, app
ModuleNotFoundError: No module named 'bot.web'

Для ясности я удалил несколько 'C: \ Users \ phill' из трассировки, прежде чем понял, что удалять это бессмысленно.

Ответы [ 2 ]

0 голосов
/ 03 октября 2019

Для того, чтобы относительный импорт работал, все пакеты и подпакеты должны быть в sys.path - для этого вам нужно запустить из каталога верхнего уровня, как в:

C:\Users\phill\zigbot>python -m bot.zigbot

Это сделает ваш текущийрабочий каталог (zigbot), доступный для sys.path, и подпакеты будут разрешены правильно

0 голосов
/ 02 октября 2019

Я думаю, что в вашем разделении есть фундаментальный недостаток, если у вас есть библиотечные зависимости через границу. Предполагая, что в вашем веб-контейнере нет импорта бот-модулей, я бы предложил разбить общий код на модуль с именем weblib или что-то в этом роде (рядом с папками bot -, nginx - и web). ).

Вы все равно не должны пытаться импортировать через потенциальные границы контейнера, поэтому просто убедитесь, что weblib находится на вашем пути или установлен в вашей виртуальной среде, или как вы хотите с этим справиться. По сути, bot и web должны работать в разных средах и иметь weblib в качестве зависимости.

Кто-то умнее меня сможет объяснить это лучше.

...