从不同的子文件夹中相对导入Python模块

8
我正在尝试使用Python中的SQLAlchemy工具之一alembic。您需要输入一个命令,它就会生成一个名为“alembic”的文件夹,并在其内部生成py文件。这些py文件需要链接到名为“myapp”的单独文件夹中的我的应用程序。但我无法将它们链接起来。它显示文件不存在,而相对导入也无法正常工作。
因此,我需要从myapp/configs/config.py文件中导入我的配置类。
/apps
+--/alembic
|----env.py <--- the calling file
+--/myapp
|----configs/__init__.py <--- has "DefaultConfig" class imported
|----configs/config.py <--- I want to import the class inside here.

在env.py文件中:

from myapp.configs import DefaultConfig

无法正常工作。
我尝试了:
from ..myapp.configs import DefaultConfig

失败了。

alembic文档中的示例代码仅使用"myapp.whatever"。

我甚至在环境变量中添加了"/apps"和"/myapp"到PYTHON_PATH。

示例错误:

File "D:\apps\myapp\lib\site-packages\alembic\command.p
y", line 97, in revision
    script.run_env()
  File "D:\apps\myapp\lib\site-packages\alembic\script.py
", line 191, in run_env
    util.load_python_file(self.dir, 'env.py')
  File "D:\apps\myapp\lib\site-packages\alembic\util.py",
 line 186, in load_python_file
    module = imp.load_source(module_id, path, open(path, 'rb'))
  File "alembic\env.py", line 5, in <module>
    from ..myapp.configs import DefaultConfig as conf
ValueError: Attempted relative import in non-package

我有点困惑,您是否运行了该项目的 setup.py 文件? - Greg
我执行了 "pip install alembic" 后,接着运行了 "alembic init alembic" 命令,并生成了文件。 - Dexter
在导入之前,尝试在env.py中将'../myapp'添加到Python的sys.path - martineau
2个回答

9
你有两种可能的解决方案:

修改你的PYTHONPATH环境变量

通过在终端中运行以下BASH / SH shell命令,将路径添加到应用程序目录:

$ export PYTHONPATH=$PYTHONPATH:'/path/to/apps'

请注意,将其添加到 PATH 环境变量中是不起作用的。如果您想了解有关 PYTHONPATH 如何管理以及模块的一般信息,请访问以下网址:http://www.stereoplex.com/blog/understanding-imports-and-pythonpath
请注意,此方法确实会影响您系统的 PYTHONPATH。强烈建议使用虚拟环境 - 以防出现问题,它不会影响您的整个系统和其他应用程序。在使用 virtualenvwrapper 时:
$ add2virtualenv '/path/to/apps'

更多详见此处

在Python脚本内添加路径

另外,你可以仅在脚本运行时添加路径,方法如下:

import sys
sys.path.append('/path/to/apps')

请将以下代码添加到您的apps/alembic/env.py文件中。

最后,在同一文件中进行以下更改:

from myapp.configs.config import DefaultConfig

请注意,您的apps/myapp文件夹还应包含__init__.py文件(可以为空),以使Python将其视为模块,正如Demian Brecht所指出的那样。

1
对我有用!alembic文件夹默认应该在应用程序模块内吗?这似乎是一种奇怪的行为。此外,为了避免使用硬路径`import sys,ossys.path.append(os.getcwd()) ` - agentargo

0

myapp 是一个自包含的应用程序,还是像 Django 中使用的那些子应用程序之一?如果它是一个自包含的应用程序,那么你正在错误的方法上进行。你真正想要做的是安装你的应用程序所需的依赖项,以便能够访问它们,而不必使用相对导入等(这是不好的实践,尤其是其他人在使用应用程序时)。

如果它是自包含的应用程序,则您可能需要执行以下操作:

现在,您应该能够通过项目中的任何位置使用alembic,只需使用import alembic即可。 编辑: 您的目录结构也有点混乱。您需要将所有特定于应用程序的模块放入另一个myapp子目录中:
myapp
    myapp
        __init__.py
        configs/__init__.py

这样做的原因是为了让您可以将myapp添加到您的PYTHONPATH中,并能够通过from myapp import foo导入应用程序中的任何模块。如果现在myapp已经在您的PYTHONPATH中,您只能访问第二个命名空间级别的子模块(即import configs),这对于明显的原因是不好的。

这是一个Flask应用程序。我不确定如何让alembic找到我的配置文件并从中获取DB SQL URI。示例只是说要做“app.config [“SQLALCHEMY_URI”]”之类的事情,但它没有定义如何获取“app”。抛出的错误是在我运行'alembic revision --autogenerate -m "test"'之后,这样我就可以创建我的初始模型。 - Dexter
只要在请求上下文中,您可以使用“from flask get current_app”来获取“app”。 - Demian Brecht
1
你只有在网站离线时才会使用alembic执行命令,因此必须是应用程序上下文。我认为我需要一些新的代码,就像在flask-alembic中一样。 - Dexter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接