在运行setuptools测试时访问包的`__init__.py`中定义的名称

0 投票
1 回答
633 浏览
提问于 2025-04-16 04:35

我开始把模块代码直接放在包的 __init__.py 文件里,即使是一些简单的包,这样做之后,这个包就成了唯一的文件。

所以我有一堆包看起来像这样(虽然它们不都是叫 pants :))

+ pants/
\-- __init__.py
\-- setup.py
\-- README.txt
\--+ test/
   \-- __init__.py

我之所以这样做,是因为这样可以把代码放在一个单独的(而且可以单独管理版本的)目录里,并且它的工作方式和如果包放在一个单独的 module.py 文件里是一样的。我把这些包放在我的开发 Python 库目录里,并在做这些事情时把它添加到 $PYTHONPATH 中。每个包都是一个独立的 git 仓库。

编辑...

与典型的 Python 包结构相比,比如 Radomir回答 中所示,这种设置让我不需要把每个包的目录都添加到我的 PYTHONPATH 中。

.../编辑

这方法效果不错,但我遇到了一个(有点晦涩的)问题:

当我在包目录中运行测试时,包本身,也就是 __init__.py 中的代码,并不一定会在 sys.path 中。这在我通常的环境下不是问题,但如果有人下载了 pants-4.6.tgz 并解压了源代码包,进入目录后运行 python setup.py test,那么包 pants 通常不会在他们的 sys.path 中。

我觉得这很奇怪,因为我本以为 setuptools 会从被测试包的父目录运行测试。但不知为何,它并没有这样做,我猜是因为通常不会以这种方式打包。

相对导入不工作,因为 test 是一个顶级包,它是作为当前目录的子目录出现在 sys.path 中的。

我希望避免把代码移到一个单独的文件中,并在 __init__.py 中导入它的公共名称。主要是因为这样做看起来对一个简单模块来说是多余的。

我可以在 setup.py 中明确地将父目录添加到 sys.path,但我不太想这样做。首先,这在理论上可能会失败,比如如果有人决定从他们的文件系统根目录(大概是 Windows 驱动器)运行测试。但主要是这感觉有点不靠谱。

有没有更好的方法?

把代码放在 __init__.py 中被认为特别不妥吗?

1 个回答

1

我觉得打包Python程序的标准方式应该是这样的:

\-- setup.py
\-- README.txt
\--+ pants/
   \-- __init__.py
   \-- __main__.py
   ...
\--+ tests/
   \-- __init__.py
   ...
\--+ some_dependency_you_need/
   ...

这样你就可以避免这个问题了。

撰写回答