Python 无法导入C++;扩展名(如果在包根目录中)

Python 无法导入C++;扩展名(如果在包根目录中),python,python-3.x,python-c-api,Python,Python 3.x,Python C Api,注意:自从问了这个问题之后,我后来发现python-m pip install-e.将使用.venv/lib/python3.8/site packages/hello-c-extension.egg链接将扩展安装到cmod,指向当前目录中的项目。在以后的提交中,我还切换到了src布局,发现它是分发控制盘的高质量软件包的一个很好的参考。但是,我仍然很想知道setup.py子命令的行为 作为部分研究的一部分,我使用一个玩具项目来为C++扩展模块构建不同的平台轮子。 看起来,当在本地构建和安装时,

注意:自从问了这个问题之后,我后来发现
python-m pip install-e.
将使用
.venv/lib/python3.8/site packages/hello-c-extension.egg链接将扩展安装到
cmod
,指向当前目录中的项目。在以后的提交中,我还切换到了
src
布局,发现它是分发控制盘的高质量软件包的一个很好的参考。但是,我仍然很想知道
setup.py
子命令的行为


作为部分研究的一部分,我使用一个玩具项目来为C++扩展模块构建不同的平台轮子。 <>看起来,当在本地构建和安装时,如果我的当前目录是项目根目录,则<强> >我不能导入C++扩展模块。< /强>这阻止了我运行单元测试,等等。我认为这是因为

成为了
sys.path
的第一个组件,因此纯Python版本被采用,而编译的扩展则没有

我怎样才能解决这个问题?我是否正确运行本地生成/安装

包结构如下所示:

$ tree hello-c-extension/
hello-c-extension/
├── LICENSE
├── Makefile
├── README.md
├── cmod
│   ├── __init__.py
│   ├── _cmodule.cc
│   └── pymod.py
├── setup.py
└── tests
    ├── __init__.py
    └── test_cext.py
我也有GitHub上的项目;我问这个问题的时候

要构建/安装,我使用:

cd hello-c-extension
python-mvenv.venv
来源。/.venv/bin/激活
python-m pip安装-U pip轮子设置工具
python setup.py build安装
现在,从当前目录,我可以导入Python模块,但不能导入相应的扩展模块。Python模块将作为当前目录中的模块而不是
站点包中的模块被拾取:

cmod import pymod中的“
$python-c”;打印(pymod)'
$python-c'来自cmod导入_cmod;打印(_cmod)'
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ImportError:无法从“cmod”导入名称“\u cmod”(/Users/brad/Scripts/python/projects/bsolomon1124/hello-c-extension/cmod/\uu init\uuu.py)
恶意删除
sys.path的PWD元素修复了以下问题:

导入系统 >>>系统路径 [“”,/Users/brad/.pyenv/versions/3.8.1/lib/python38.zip',“/Users/brad/.pyenv/versions/3.8/lib/python3.8',”/Users/brad/.pyenv/versions/3.8.1/lib/python3.8/lib dynload',“/Users/brad/Scripts/python/projects/bsolomon1124/hello-c-extension/.venv/lib/python3.8/site-python3.8',”,“/Users/brad/Scripts/projects/hello/projects/python3.8/bsolomonc-extension/v/lib/python3.8/site packages/hello_c_extension-0.4-py3.8-macosx-10.15-x86_64.egg'] >>>删除系统路径[0] >>>从cmod导入_cmod;打印(cmod)
最后,更改目录也可以解决问题:

$cd。。
$python-c'来自cmod导入_cmod;打印(_cmod)'
这真的是。。。它应该如何工作?在这种情况下,为扩展模块运行单元测试的正确方法是什么

系统信息:

$python-V
Python 3.8.1
$uname-mrsv
达尔文19.4.0达尔文内核版本19.4.0:Wed Mar 4 22:28:40 PST 2020;根目录:xnu-6153.101.6~15/RELEASE_X86_64 X86_64
问题的原因 这真的是。。。它应该如何工作?在这种情况下,为扩展模块运行单元测试的正确方法是什么

Python从
sys.path
导入。这意味着它将搜索导入的每个目录,从索引
0
sys.path
中的最后一项

请注意,解决问题的一种方法是在导入之前添加以下内容:
sys.path.append(sys.path.pop(0))
。这仍然允许本地导入,但意味着首先搜索
站点包
和标准库

我怎样才能解决这个问题?我是否正确运行本地生成/安装

我将回答下面的第一个问题

是的,您的构建/安装很好,但要解决导入问题,您需要稍微调整一下

解决问题 切换到
src/cmod
布局。一个很好的链接是

评论中讨论了这种方法,自从提出这个问题以来,您实际上已经实现了这一点。()

我现在引用那篇文章的一些内容;这比我能解释得更好

src目录是一种更好的方法,因为:

  • 你得到了进口平价。当前目录隐式包含在sys.path中;但从站点软件包安装和导入时并非如此。用户将永远不会拥有与您相同的当前工作目录
该约束在测试和包装中都具有有益的含义:

  • 您将被迫测试已安装的代码(例如,通过在virtualenv中安装)。这将确保部署的代码正常工作(正确打包),否则测试将失败。很早。在发布损坏的分发版之前

  • 您将被迫安装分发版。如果您在PyPI上上传了一个缺少模块或依赖项已损坏的发行版,那是因为您没有测试安装。仅仅成功地构建sdist并不能保证它会真正安装


pip install-e。
将不再把东西弄乱。

建议将模块目录放在子目录中,而不是直接放在包的根目录中,以避免此问题,并强制使用(任意)安装版本。另一种选择是使用@L.Kärkkäinen?我在上面链接的文章部分似乎特别提到了这个问题。(讽刺的是,尽管有警告,“不要将源代码放在名为src或lib的目录中。这使得不安装就很难运行。”
pip install-e.
使安装变得足够容易,因此这不再是一个问题。工作