我试着通读关于兄弟姐妹导入的问题,甚至 软件包文档,但我还没找到答案。

结构如下:

├── LICENSE.md
├── README.md
├── api
│   ├── __init__.py
│   ├── api.py
│   └── api_key.py
├── examples
│   ├── __init__.py
│   ├── example_one.py
│   └── example_two.py
└── tests
│   ├── __init__.py
│   └── test_one.py

示例和测试目录中的脚本如何从 API模块和从命令行运行?

另外,我希望避免对每个文件都使用难看的sys.path.insert。肯定 这可以在Python中完成,对吧?


当前回答

为了防止在Eclipse上使用Pydev的人在这里结束:您可以使用Project->Properties将兄弟的父路径(以及调用模块的父路径)添加为外部库文件夹,并在左侧菜单Pydev- pythonpath下设置外部库。然后你可以从你的兄弟导入,例如from sibling import some_class。

其他回答

如果您正在使用pytest,那么pytest文档描述了如何从单独的测试包引用源包的方法。

建议的项目目录结构为:

setup.py
src/
    mypkg/
        __init__.py
        app.py
        view.py
tests/
    __init__.py
    foo/
        __init__.py
        test_view.py
    bar/
        __init__.py
        test_view.py

setup.py文件的内容:

from setuptools import setup, find_packages

setup(name="PACKAGENAME", packages=find_packages())

以可编辑模式安装软件包:

pip install -e .

这篇文章引用了Ionel Cristian matrie什的博客文章。

七年之后

由于我把答案写在下面,修改sys.;Path仍然是一种快速而肮脏的技巧,适用于私有脚本,但是已经有了一些改进

安装包(在virtualenv中或不在virtualenv中)会给你想要的,尽管我建议使用pip来完成,而不是直接使用setuptools(并使用setup.cfg存储元数据) 使用-m标志并作为包运行也可以(但是如果您想将工作目录转换为可安装包,则会有点尴尬)。 具体来说,对于测试,pytest能够在这种情况下找到api包,并负责sys. exe。给你的路径技巧

所以这取决于你想做什么。但是,在您的情况下,由于您的目标似乎是在某种程度上制作一个适当的包,因此通过pip -e安装可能是您的最佳选择,即使它还不完美。

旧的答案

正如在其他地方已经说过的,可怕的事实是,你必须做一些丑陋的hack来允许从__main__模块的兄弟模块或父包导入。该问题在PEP 366中有详细说明。PEP 3122试图以更合理的方式处理导入,但Guido拒绝了它

唯一的用例似乎是运行发生的脚本 在一个模块的目录中,我总是把它看作一个 反模式。

(在这里)

不过,我经常使用这种模式

# Ugly hack to allow absolute import from the root folder
# whatever its name is. Please forgive the heresy.
if __name__ == "__main__" and __package__ is None:
    from sys import path
    from os.path import dirname as dir

    path.append(dir(path[0]))
    __package__ = "examples"

import api

这里的路径[0]是运行脚本的父文件夹,目录(路径[0])是顶级文件夹。

虽然我还不能使用相对导入,但它确实允许从顶层(在示例api的父文件夹中)进行绝对导入。

我想评论一下np8提供的解决方案,但我没有足够的声誉,所以我只想说,你可以完全按照他们建议的那样创建一个setup.py文件,然后执行pipenv install——dev -e。将其转换为可编辑的依赖项。然后你的绝对导入将工作,例如从api。API import foo,你就不必在系统范围的安装上瞎折腾了。

文档

我还没有对python学有必要的理解,以了解在不相关的项目之间共享代码的预期方式,而没有兄弟姐妹/亲戚导入黑客。在那一天到来之前,这就是我的解决方案。用于从..导入内容的示例或测试。\api,它看起来像:

import sys.path
import os.path
# Import from sibling directory ..\api
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/..")
import api.api
import api.api_key

你不需要也不应该侵入系统。路径,除非它是必要的,在这种情况下,它不是。使用:

import api.api_key # in tests, examples

从项目目录运行:python -m tests.test_one。

你可能应该把测试(如果它们是api的单元测试)移动到api内部并运行python -m api。测试运行所有测试(假设有__main__.py)或python -m api.test。Test_one来运行Test_one。

你也可以从示例中删除__init__.py(它不是Python包),并在安装api的virtualenv中运行示例,例如pip install -e。在virtualenv中,如果你有正确的setup.py,就会安装API包。