简体   繁体   English

从 python 中的同级文件夹导入 function 会产生奇怪的错误

[英]Importing a function from a sibling folder in python producing strange errors

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.我有一个正在运行的脚本“zigbot.py”,但我正在重组为 dockerize,现在我完全质疑我的编码能力。 What I'm trying to do is have a telegram-bot container, and a 'web' container (FLASK), and a nginx container.我想要做的是有一个电报机器人容器、一个“网络”容器(FLASK)和一个 nginx 容器。

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.在 zigbot.py 旁边,我有一个文件夹 - 'bot',其中包含我的许多脚本和函数。在尝试from bot.somescript import a_function时,我收到一个又一个错误。

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.运行下面的代码时,我得到了一系列奇怪的错误——下面列出的一个显示 ImportError——它在 funcs 中找不到“onboard”,但它肯定存在。 Before the restructure, this was working.在重组之前,这是有效的。 If I comment out 'onboard' it errors on every function in the list.如果我注释掉“板载”,则列表中的每个 function 都会出错。

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'

So I tried adding a.bot.conversation for (relative?) import, but this produces an even weirder error.所以我尝试为(相对?)导入添加 a.bot.conversation,但这会产生更奇怪的错误。 I've included the code, the error, then the function I'm trying to import below:我已经包含了代码、错误,然后是我尝试在下面导入的 function:

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对话.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.最后,我想我离问题越来越近了,我将 go 回到我认为应该导入的方式。 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. From bot.funcs import x,y,y... 我在 funcs.py 中查看,这就是它从我的 Flask web 应用程序中导入其他代码的方式,但它不喜欢它。

funcs.py函数.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'

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.因此,我将导入更改为 go 上一级,因为 web 比bot高两个级别 - 其中包含我要导入的脚本。 So zigbot>bot>bot>funcs.py trying to import from zigbot>web>app>所以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

This obviously doesn't work either.这显然也不起作用。 Given my structure of having bot and web how do I get this to work?鉴于我拥有botweb的结构,我该如何让它工作? I even tried pulling the scripts out of the second 'bot' folder but I get the same issues.我什至尝试将脚本从第二个“bot”文件夹中拉出,但我遇到了同样的问题。 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.最后,我最奇怪的错误可能会为我做错了什么提供线索,如果我将 funcs.py 上的导入更改为 go 上一级而不是两级,我会得到一个更奇怪的回溯。

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'

For clarity I removed some 'C:\Users\phill' from the tracebacks before realising it was pointless to remove that.为了清楚起见,我从回溯中删除了一些“C:\Users\phill”,然后才意识到删除它是没有意义的。

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 the bot -, nginx - and web -folders).假设您的 web 容器中没有机器人模块的导入,我建议将共享代码分解为名为weblib的模块或其他模块(与bot一起 -、 nginx - 和web

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.但是,您仍然不应该尝试跨潜在容器边界导入,因此只需确保weblib在您的路径中或安装在您的虚拟环境中,或者您想要处理它。 Basically, bot and web should run in separate environments and should have weblib as a dependency.基本上, botweb应该在不同的环境中运行,并且应该将weblib作为依赖项。

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:为了使相对导入工作,所有包和子包必须在 sys.path 中 - 要实现这一点,您应该从顶级目录运行,如下所示:

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

This will make your current working dir (zigbot) available to sys.path and the subpackages will be resolved correctly这将使您当前的工作目录(zigbot)可用于 sys.path 并且子包将被正确解析

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM